I have a Game Center game that allows players to make multiple moves per turn. In iOS 6, Apple implemented a great feature in saveCurrentTurnWithMatchData that allows you to do just that- it saves the data to game center to prevent cheating by repeatedly redoing a move for instance, without advancing to the next player.
The problem is, I have discovered that this actually triggers the same Push Notification taht gets sent when the player does end their turn. So other players in the game will see a badge on the app's icon and mistakenly think it's their turn when it isn't.
Has anyone found a workaround for this? Any way to call saveCurrentTurnWithMatchData without sending a push notification? If not, this seems like a design flaw that should probably be brought to Apple's attention.
I agree, this seems like a design flaw. I am also developing a turn-based game whereby a player can take several actions before passing control over to the next player. Meanwhile, I want other players to witness every action while they are looking at the game. If the other players are not running the app, I want them to receive a push notification only when the control is passed to another player.
Instead of using saveCurrentTurnWithMatchData:, I use endTurnWithNextParticipants: but I specify the current player rather than the next. This seems to do the trick:
NSTimeInterval interval = 86400; // seconds in a day
[currentMatch
endTurnWithNextParticipants:[[NSArray alloc] initWithObjects:currentMatch.currentParticipant,nil]
turnTimeout:interval matchData:[self packMatchData]
completionHandler:^(NSError *error) {
if (error) {
// handle error
}
}
];
Related
I'm using the SetSDK to show users the available bike share count at their nearby station whenever they leave their home. I'm following the example available in the pod documentation but am not getting the notification. Here is my code,
SetSDK.instance.onDeparture(.home) { notification in
// below is my code using the notification
let bikeStationCount = getAvailableBikes(stationsNear: notification.location)
showNotification(withCount: bikeStationCount.count, atStation: bikeStationCount.station)
}
But I'm not getting my app to show any notification, any idea what is wrong?
It looks like your code is correct. The only thing to keep in mind is that the SetSDK will learn the user's home over time, with most users it usually takes 1-2 days for it to have enough certainty to call a place Home.
Have you had a chance to let the SDK learn long enough that it is giving you notifications now?
Hey, cool use-case!
I have an application that can detect accidents, it is really important for us to alert users using vibration and alert sound if an accident is detected.
My questions are:
Is it possible to add long vibration in application by using custom sounds or something that apple might be ok with?
If I use private apis, is it possible to convince apple to approve my app considering that the use case is really critical?
Two questions here, really.
1st one: haptic feedback / control vibration on iOS / custom iOS patterns
No, it can't be done, even in the new Apple Watch without Jailbreaking your phone. You can have a look at this keyboard mod (needs Jailbreak). Here you have some code but it needs Jailbreaking your phone.
If you need to alert your users I recommend just playing the default vibration inside a while. Sleep the current thread for 1 sec, then vibrate again until some boolean flag changes. Objective-C Pseudocode:
while (!endVibrationAlert) {
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
[NSThread sleepForTimeInterval:1];
}
// when user touches some button to dismiss alert
self.endVibrationAlert = true;
2nd one: never ever try to bypass Apple's reviewing system. Abide by the rules. For your 1st version, maybe it passes. Then, in the next update your App can get rejected.
I am using iOS 6 Game Center API for turn based games.
When the device is disconnected from internet
In the completion handler of the method
[currentMatch endTurnWithNextParticipant:nextParticipant matchData:data completionHandler:^(NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
//save the new state of the game
}
I get an error. But then, game center standard UI that displays matches list, says "Their turn". when connected again it changes to "Your turn".
The code from famous tutorial at http://www.raywenderlich.com/5509/beginning-turn-based-gaming-with-ios-5-part-2 has the same exact problem.
How I should handle this problem?
If you are using iOS 6 Game Center API then you will have to use
-endTurnWithNextParticipants:turnTimeout:matchData:completionHandler:
because...
–endTurnWithNextParticipant:matchData:completionHandler: Deprecated in iOS 6.0
http://developer.apple.com/library/ios/#documentation/GameKit/Reference/GKTurnBasedMatch_Ref/Reference/Reference.html
The thing is, that when you use GC methods that change status of the match (matchData and synchronization info in this case), data is uploaded to the GC server so that other player(s) get the update. If you're disconnected and ignore the error, your local GKTurnBasedMatch and its matchData change, as well as your synchronization info (which is used to determine if it is your turn to act among other things).
However, since you are diconnected, only your local instance of GCTurnBasedMatch is updated (you get error so that you app is aware of that). When you're reconnected, your app authenticates the user and updates match state (if you're following the tutorial code). Updating match data reverts the sync data (so it's still your turn).
At this point, you should either submit the turn again (provided that you cached gameData that was passed to GC while you were disconnected) and/or call updateMatchData so that your local GKTurnBasedMatch and its matchData get in sync with what's on the server. You should also re-layout your game board with previous turn's data if you didn't re-submit turn after reconnection.
The following code is called once upon applicationDidFinishLaunching:; however, it runs each time my app re-enters the foreground again.
[localPlayer authenticateWithCompletionHandler:^(NSError *error) {
if (localPlayer.isAuthenticated)
{
// Some implementation
}
}];
This makes sense, according to the Game Kit Programming Guide:
... it also retains your completion handler for later use. Each time your application is moved from the background to the foreground, Game Kit automatically authenticates the local player again on your behalf and calls your completion handler to provide updated information about the state of the authenticated player.
Is there any way to delay this authentication until Game Center is actually needed? The reason I ask is that I would like to avoid showing the "Welcome back, userX!" banner each and every time the app is brought to the foreground.
No, you can't, at least not with public APIs.
In just about every example of submitting achievements to Game Center, I see this code
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error != nil)
{
// Retain the achievement object and try again later (not shown).
}
}];
Problem is, that one little comment is about 99% of the work. I've spent the last few hours trying to figure this out and it seems to be an endless set of edge cases of sending and resending and save and loading data.
Does anyone know of a nice tutorial (or sample code) on this that actually explains the hard part?
It's not as simple as just saving them to a file and loading them later. You get into trouble when you start having to retain multiple achievements and submit them later and then they all come back failed (in blocks!) and you have to save them again... quickly/safely... because the App might quit and you don't want to loose them.
I'm pulling my hair out.
I don't think you need to pull your hair out.
I think the basic model is this:
(a) Independent of Game Center, your game has a saved state (which you always need anyway, to restore the player to where he was when your game is quit/backgrounded). This state should include all the normal stuff you need to restore your game state, plus it should include flags for all of the achievements in your game.
(b) Game Center also stores all of the achievements in your game. When you connect to Game Center, you download the signed-in player's achievements. (Complications arise as to who the signed-in player is, but your question is not about that, so let's assume the "one true player" is always the signed-in Game Center player.)
(c) Whenever the player makes an achievement, first update the appropriate achievement flag in your game's saved state data. Second, try to tell Game Center about that achievement. If it works, update your copy of Game Centers achievements with the new data.
(d) If it doesn't work, you have an achievement marked in your persistent state that is not marked in your copy of the Game Center state. At various convenient times (e.g., whenever another achievement is earned, when you end a level, when your app starts, when you app quits, etc.) check if there are any discrepancies between what is in your own state vs. what is in the Game Center state. A discrepancy is an update that you need to re-send to Game Center. Try to send, but if it fails again, just wait until the next opportunity (e.g., whenever another achievement is earned, when you end a level, when your app starts, when you app quits, etc.) to try again. You will never lose the data because it's in your local, true picture of the user's state. (The only way you'd lose it is if the user uninstalls your app before you've been able to successfully get it to Game Center, but then, what can you do?)