2

I'm totally lost with how to implement a turn-based game. I've been trying to use the GKLocalPlayerListener methods to handle turn-based in iOS9. The only method that ever fires is receivedTurnEventForMatch, which leaves me with no method that I know of that calls an end game routine for each player. I am trying to handle turn-based matches inside of my app using the Game Center match maker view controller and delegate methods. I read that GKLocalPlayerListener methods work for matches when going through the actual Game Center app (Apple docs don't mention this). So if that's true, then GKLocalPlayerListener is not an option for my app?

What can I do to detect when a match ends? I want to keep a win-lose record for each player, so it's important that a routine is called for each player when a match ends.

codeflow
  • 25
  • 3

2 Answers2

3

The lifecycle of a turn based match looks like this:

  1. Create a match
  2. Invite others
  3. Others join
  4. Players take turns and pass the match object around (your game logic decides the order)
  5. Players send exchanges back and forth (optional)
  6. Players start leaving
  7. ----because they have been eliminated
  8. ----because they quit
  9. ----because they timed out
  10. Someone Wins

If you are not the active player, you are notified when steps 3, 4, 7, 8 and 9 happen by playerReceivedTurnEventForMatch firing; however, as you can see from my answer here https://stackoverflow.com/a/34458493/1641444 playerReceivedTurnEventForMatch fires for a lot of different conditions, and it doesn't tell you which one triggered it. You have to discern that based on the status of the players, which player is the active player, and whatever other information you track in the match object.

You are notified of #5 by playerReceivedExchangeRequest firing (and Replies and Cancellation functions).

Your game logic will decide when to trigger #7. My preference is that the match object comes to the eliminated player, they are recognized as defeated, and calls participantQuitInTurnWithOutcome

Players decide when to trigger #8 by quitting, and the code calls either participantQuitInTurnWithOutcome or participantQuitOutOfTurnWithOutcome depending on their state.

Condition #9 is a real pain in the ass. Between limitations in the game design and outright bugs, timeouts can create several unrecoverable edge cases. Handling timeouts warrants its own full answer.

Finally, #10 is triggered by calling endMatchInTurnWithMatchData. GKTurnBasedEventHandlerDelegate and handleMatchEnded were deprecated in IOS7. When using GKLocalPlayerListner, you'll be notified of #10 by yet another occurrence of playerReceivedTurnEventForMatch

Edit--Clarifications based on followup questions:

Yeah, exactly. In your sendTurn function, when the game is over, don't call endTurnWithNextParticipant. Instead, set the each participant's status to indicate who won and who lost, and then call endMatchInTurnWithMatchData.

The other players will see playerReceivedTurnEventForMatch fire. You can discern from the match status and the player status that the game is over and decide what actions to take for that recipient.

Community
  • 1
  • 1
Thunk
  • 4,099
  • 7
  • 28
  • 47
  • Thanks Thunk, I've read several of your other answers on SO. Very insightful. My endMatchInTurnWithMatchData is in my sendTurn method, so are you saying when that is fired for any player it should also yield the occurrence of player:receivedTurnEventForMatch? Which then I can handle my end-game methods in that GKLocalPlayerListener method, given that the match is over (check using if statement or something)? – codeflow Mar 26 '16 at 17:53
  • @codeflow, thanks for the kind words. Yeah, exactly. I updated the answer to be a little more clear about that. – Thunk Mar 26 '16 at 18:28
  • Thanks for the followup. I know this is a bit unrelated to my original question, but might you have any inkling as to why receivedTurnEventForMatch is the only method that fires? If it helps, I have used this approach to add GKLocalPlayerListener: http://stackoverflow.com/questions/31971430/warning-when-adding-event-listener-to-turn-based-ios-game – codeflow Mar 26 '16 at 18:39
  • No, and I find it very frustrating. I've opened a bug, asking for an eventType parameter to be added to the function call so we know which of the ~dozen or so conditions triggered it. No response from Apple. Let me know if there's anything else I can add. If the posted answers have been helpful, please don't forget to vote/accept! :) – Thunk Mar 26 '16 at 18:51
  • I will also enforce this bug you've submitted as that is an excellent addition and would eliminate the need to write a series of convoluted workarounds. Thanks! – codeflow Mar 26 '16 at 18:56
  • @Thunk, do you know of any basic iOS 9 Turnbased example code? I swear no one uses this shitty API – sdc Jul 15 '16 at 06:04
  • @sdc, Unfortunately, I haven't seen anyone create any new tutorials on this. I'm currently studying the new stuff announced in IOS10 and will probably move from `GKTurnBasedMatch` to the game session stuff, as well. – Thunk Jul 31 '16 at 20:09
  • Hi, I have a similar issue and im getting very frustrated. Bundle ID register to Gamecenter + Notifications I'm sending a endTurnWithNextParticipants with no errors but I do not get a : Push Notification on the other device nor the GKTurnBasedEventListener functions are beeing called. – Apostolos Jun 18 '17 at 08:25
0

To end a match, you should have your game call endMatchInTurnWithMatchData:completionHandler:

If you've implemented GKTurnBasedEventHandlerDelegate protocol on an object, your handleMatchEnded will get a push event.

More details in Apple's programming guide

Mathew Spolin
  • 371
  • 1
  • 11
  • Will the endMatchInTurnWithMatchData be called for all players? I need to add to a total number of games counter for each player so I need something that fires for each player regardless if they're currently playing. Also is it really wise to use handleMatchEnded since GKTurnBasedEventHandlerDelegate is deprecated? – codeflow Mar 26 '16 at 17:45