I am developing a social game that uses Game Center and had a question about informing one of the player's client that it will be used as the "server". At first I thought to send a data packet to the GKPlayer which was returned with the method:
- (void)chooseBestHostingPlayerWithCompletionHandler:(void (^)(GKPlayer *player))completionHandler
The only issue I can see with using this method is if it is possible for another player in a match to pick someone else who their client thinks would be the best "server". At the moment I am assuming since this method is under GKMatch that it already takes into consideration all current players in the game and each application that runs this match should get the same GKPlayer object returned. Is this true?
All players in the match must call chooseBestHostingPlayerWithCompletionHandler, as per the documentation. If that is done, all players receive the same answer: either a specific GKPlayer or nil.
Related
I'm trying to send an exchange to another player in a GKTurnBasedMatch. When I send it, my completion handler gets a big error message, with these descriptions:
The requested operation could not be completed because the session is in an invalid state.
Game is not active, session state is Matching
I want the match to start when there are just two players, but to allow a total of 16 players. So naturally I'm setting maxPlayers = 16 and minPlayers = 2. I'd thought that would automatically start the match once two players were seated, but it's not so.
I've tried to do this once the match has two players, :
if match.participants?.count == 2 {
match.status = GKTurnBasedMatchStatus.open
}
But then I'm told that status is read-only. I can't manually set it.
Now, with a regular GKMatch, I officially start the match by calling:
GKMatchmaker.shared().finishMatchmaking(for: match)
But there doesn't seem to be a similar thingy for GKTurnBasedMatch.
How do I actually get the match started, so I can send an exchange between the two players?
Man, the documentation on GKTurnBasedMatch is sparse.
Here's the thing: you don't actually start a GKTurnBasedMatch explicitly. You only end it explicilty.
During gameplay, you just pass the turn from one active player to another active player. The game technically starts as soon as the first player is seated.
The problem I was having is that I had passed the turn when there was no other active player. So I accidentally told Game Center to assign the turn to an empty seat. So when the error message told me
Game is not active, session state is Matching
It meant that the current seat was empty and still looking for a player to fill it. The game apparently goes out of active status any time the current player's status is Matching (which denotes an empty seat).
Why on earth this would affect sending exchanges, whose whole purpose is to enable communication between any players, no matter who the current player is, is beyond me. But there you go.
The solution: make sure that the current turn is held by an actual person, and is not an empty seat. Then you can send exchanges. Otherwise you can't.
What would be the best way to uniquely identify an MSConversation when developing an iMessages application?
In my case I want to give to a game object an ID of the conversation where it belongs to.
Take the localParticipant ID, add to it the remoteParticipants ID ;)
Something like that :
var conversationID = yourConversation.localParticipantIdentifier
for participant in yourConversation.remoteParticipantIdentifiers {
conversationID += participant
}
EDIT:
As noticed in comments, by doing so, you could end up with a very long ID. So the idea is to apply an hash to it, to have a constant size (MD5 is suffisant, we don't need something secure here). If it is still too long, you could crop that hash, but be aware that in that case there is a small probability for two conversations to have the same ID (depending on how much your crop).
The current top answer has a corruption issue in that if a new person is added to a group chat (or if someone is removed) your hashed ID will change.
A more elegant solution in my opinion is to just create your own serial number at the time of the first message being created and add it as meta-data to your message itself. (Using NSURLComponents of course). Then just grab that anytime a message is opened (thus launching your message app) and use that ID. Just keep it in the header of any message sent/received.
But, it depends on what you are trying to do really. The solution I've provided is great for turn-based multi-player games. It might not be good for other scenarios.
When doing a PurchaseOrderQuery in QBXML I am trying to get Quickbooks to only return purchase orders that are not yet processed (i.e. "IsFullyReceived" == false). The response object contains the IsFullyReceived flag, but the query object doesn't seem to have a filter for it??
This means I have to get every single Purchase Order whether or not it's received, then do the filtering logic in my application - which slows down Web Connector transactions.
Any ideas?
Thanks!
You can't.
The response object contains the IsFullyReceived flag, but the query object doesn't seem to have a filter for it??
Correct, there is no filter for it.
You can see this in the docs:
https://developer-static.intuit.com/qbSDK-current/Common/newOSR/index.html
This means I have to get every single Purchase Order whether or not it's received, then do the filtering logic in my application - which slows down Web Connector transactions.
Yep, probably.
Any ideas?
Try querying for only Purchase Orders changed or modified (ModifiedDateRangeFilter) since the last time you synced.
Or, instead of pulling every single PO, keep track of a list of POs that you think may not have been received yet, and then only query for those specific POs based on RefNumber.
Or, watch the ItemReceipt and BillPayment objects, and use that to implement logic about which POs may have been recently filled, since BillPayment andItemReceipt` objects should get created as the PO is fulfilled/received.
I'm trying to get two physicsBody, that are already in contact with each other (in fact they overlap because physicBody.collisionCategory = 0; for both physicsBody's), to restart/re-register/re-trigger their contact, on command. I've been unable to do this even though I tried to get body1 to move by one pixel within body2 to re-trigger the contact. I've also deleted one of the physicsBody's & re-instantiated it several seconds after that to re-trigger the contact. But nothing works. Is there some sort of method or technique to restart the contact process while both bodies are already in contact?
So, to make things a little clearer:
1) SpriteHuman walks onto SpritePanel.
2) -(void)didBeginContact:(SKPhysicsContact *)contact registers the contact.
3) I call a method that starts step 2 again, while SpriteHuman doesn't move and is still contacting SpritePanel.
You can set a BOOL property to YES for your player object if it contacts a certain object. This will allow you to continuously run whatever code you need to run. Just remember to do also set the BOOL back to NO when contact is lost.
I am working on building a game where a user is able to build their own map to explore. Using GameKit and Game Center is it possible to challenge another user to play that map that was just created?
If so, how does this work so that the other user can see the graphics, data, etc that was created within another users game instance?
It would depend entirely on how your game is designed. GameCenter doesn't really care what sort of data you are sending in a match, as long as it adheres to the limits Game Center Places on messages.
The common factor is that you need to find a way to serialize your custom level into a format that can be sent over Game Center, then write deserialization methods to get the data into the map's format. If your maps are persistent, you can probably just send the file (unless you are using a very inefficient representation) and then use your regular methods for making a map out of the file.
For simplicity, lets say that you're making a turn-based game with a Minecraft-like board, so the only thing that you can edit is the height of each block. You might send a special turn with the JSON-serialized equivalent of
NSArray* board = //Array of arrays of NSNumbers with the heights of each block.
NSArray* turn = #[#"This is the turn that sends the board", board];
//serialize this into a NSData with JSON then send it with endTurnWithMatchData:
Then in your receivedTurnEventForMatch: method, you test for the special string in index zero that turn, or just expect it to be the first turn, and then use it to create the board, and programmatically end your current turn with no action if it is the other player's turn, or let the player receiving the custom map make his first turn.
For more ambitious custom content like images you would have to get the maximum size turn you can currently send and then break up the images into chunks to send.