I know there are already some posts about this topic, but I cannot find the answer I need and I do not know where to start.
I would like to create an online multiplayer game for the iPhone where players can play together against each other over the Internet. For example a 2 player racing game where once the 2players are matched and connected they can both control their cars in real time against each other. E.g like mario cart.
I know that the game kit does thus but only over Bluetooth or over the same wifi network. I would like this to be over the Internet (wifi only) where players can play against each other around the world.
I know there are already some frameworks to do this. But they are costly and depend on the number of connections. Is there a cheap or dare I say, free way of doing this? Like have game kit do the matching and then the connections and sending data is done some other way? Like having the iPhones host the games? Rather than having a dedicated server. I do not have the budget nor the knowledge and experience to create a dedicated server.
The matching is simple. There are 30 levels and any 2 players wanting to play the same level are matched.
Any links or book recommendations are welcome. I have very limited networking knowledge and do not know where to start.
I can read and learn the techniques even if they are technical but I will need the right resouces to allow me to make a start
Thanks in advance.
You actually can do exactly what you are looking for using the Game Kit API's. Basically, you create a match using the GKMatchMakerViewController. To make the match you use the GKMatchMakerViewController to start looking for other players, once it finds other players it notifies the GKMatchMakerViewControllerDelegate that a match has been found and will pass the GKMatch object. Then you need to have an object which implements the GKMatchDelegate protocol to handle the actual data. You set your delegate object to be the delegate of the GKMatch you are passed, and then use methods from the GKMatchDelegate protocol such as – match:didReceiveData:fromPlayer: and methods from GKMatch to send data.
Heres some example code to help with that explanation. This is just the bare essentials, you of course need to implement your gameplay stuff, and some error handling.
Also, you can find the documentation you need at these four links
GKMatchMakerViewController GKMatchMakerViewControllerDelegate GKMatch GKMatchDelegate
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID{
if(matchStarted){
Packet *msg = (Packet *)[data bytes];
//do whatever you want with the data received from other people
}
}
-(void)sendPosition{
//call this to update the other players devices (should be self explanatory)
NSError *error;
Packet msg;
//Here the msg object is actually a typedefed struct name Packet. I use this to send and receive data
NSData *packet = [NSData dataWithBytes:&msg length:sizeof(msg)];
[myMatch sendDataToAllPlayers: packet withDataMode: GKMatchSendDataUnreliable error:&error];
if (error != nil)
{
// handle the error
}
}
#pragma mark MatchSetup
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match{
[self dismissModalViewControllerAnimated:YES];
self.myMatch = match; // Use a retaining property to retain the match.
self.myMatch.delegate = self;
if (!matchStarted)
{
// Insert application-specific code to begin the match.
}
}
What you're looking for is a GameKit "hosted match" wrapper, which possibly does exist. The caveat is that Apple doesn't host these types of matches, your own server does. So, you'd need a webhost, and those aren't usually free. Amazon's AWS is free for a micro-instance, but depending on scale you would probably top out with enough synchronous play.
I'm more interested in learning about potential GameKit wrappers now that you've brought it up. Can you comment on what you've found, you mentioned that they're expensive and have limits on connections.
PS - Apple's limit is up to 16 players
You should check out real-time peer-to-peer networking service PubNub as it sounds like a perfect match for your project.
I found PubNub very easy to implement even with my modest programming knowledge. Integrating different platforms was also easy as there are SDK's for most common languages. I had a PHP based web page that served as a scoreboard for my iOS based app.
Related
I need to check the internet connection of a user for one time.
I thought of something like Device.isConnectedToTheInternet but I didn't find something similar...
Every solution that if found was like an internet monitor over time, but that's not exactly what I need.
Someone ideas?
Thanks, Boothosh
As Rob Napier mentioned, it looks like the only thing readily available is the NWPathMonitor, which you can use to check the 'connectivity' to a certain location, like www.google.com, or something else that would be relatively trustworthy to be available 24/7, or just the URL you are about to try and use. Here is a short HackingWithSwift tutorial for NWPathMonitor.
I know this isn't exactly your current situation, but in my projects (and a lot of peoples projects) using an API like AlamoFire is pretty common, and has a ton of usefulness for creating GET/PUT/POST/DELETE requests and of course, has a NetworkReachabilityManager which can be used to make a convenient global function for a simple true/false result for 'isConnectedToInternet' like this:
/*
Connectivity
Struct
Utilizes AlamoFire to check for network availability.
isConnectedToInternet should return true in all cases the phone has access (Cellular, No cellular + wifi, Cellular + wifi, wifi)
*/
struct Connectivity {
static let sharedInstance = NetworkReachabilityManager()!
static var isConnectedToInternet:Bool {
let connected = self.sharedInstance.isReachable
return connected
}
}//end Connectivity
See NWPathMonitor().currentPath. It will tell you the current path. This is only occasionally useful, since "connected to the internet" is not a meaningful condition. There is not concrete definition of "the internet." But you can use the NWPath to answer some questions you probably are looking for. The fact that there is an NSPath available does not mean that you can actually connect to something on "the internet." The only way to know that is to send a packet and get a packet back. So if your real question is "can I connect to a specific host," then you're going to need to send packets to that host (and that still won't prove that you can send packets to the host in the future).
All that said, there is a little UI-level usefulness to asking "if I tried to connect, would it certainly fail?" And currentPath can help you answer that. It just can't tell you if it would succeed.
How to use ios 5 sdk's asynchronous http get requests to handle redirected urls?
I have found the knowledge in bits and pieces. All the solutions assume some important piece of info to be known to the user. This is very difficult to figure out for a person who who has just started coding ios that to beginning with ios5 sdk.
I know a lot of people might ask to go and read the doc, which somehow have the same issue but please, could someone explain the concept in simple terms...a working code along with the little detail what peice goes where?
Thanks for your time!
AFNetworking provides a good foundation of code for dealing with network requests, and this page specifically has information regarding redirects. It doesn't look like the changes proposed in that comment thread have been committed yet but in any case check it out and see if that helps.
In short, kcharwood suggests subclassing the whichever operation you choose to use and overriding -(NSURLRequest *)connection:willSendRequest:redirectResponse: like so:
- (NSURLRequest *)connection: (NSURLConnection *)inConnection
willSendRequest: (NSURLRequest *)inRequest
redirectResponse: (NSURLResponse *)inRedirectResponse
{
if (inRedirectResponse) {
//Create your mutable request to return in the redirect scenario
} else {
return inRequest;
}
}
I developed an iPhone App that uses the GameCenter. To support different levels of my game I set the playerGroup within the GKMatchRequest class. If the match is started by an automatic match making process both users knows the playerGroup, but if the invitation process is used, the invitee does not know the playerGroup.
I tried to read the playerGroup within the method
- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match
by using
[viewController matchRequest].playerGroup, but the property playerGroup always return 0, instead the right player group.
Does anyone have an idea how to solve this problem. I need to know the playerGroup to load the right level.
Thank you very much for your help
As far as I know, this is a built in limitation of Game Center. I have been struggling with it too, and asked on several forums, including Apples devforums, without any response. I've written a bug report to Apple and I suggest you do the same.
As a workaround in my own game, where I have several different rulesets that players choose from and where players have to share the same rules for multiplayer matches to work, I put in a "double check" after the game actually starts to make sure everyone is on the same rules: Just in case someone was invited and is using the wrong rules.
What I did is, as soon as the game starts (which you should detect for in both the didFindMatch method of the GKMatchMakerViewControllerDelegate and in match:player:didChangeState: in GKMatchDelegate) I let the players enter the game and then send out packages containing the rules they use to all the other players. When they receive this data, they match it with their own rules and if anyone is using the wrong rules, the game will put up an alert and disconnect the match.
It's a bit ugly, and it's very clear that Apple ought to implement a way to set a GKMatchRequest for a GKMatchMakerViewController when initialized by an invite. But at least it works.
I stumpled upon the same problem. As a workaround I am sending a handshake with all relevant game customization info through the GKMatch object. I send the data with GKMatchSendDataReliable DataMode so the handshake doesn't fail.
After all information is collected by the clients the actual game logic is created and started on its basis.
You can check the Player Group of a match request like this.
func player(player: GKPlayer, didAcceptInvite inviteToAccept: GKInvite) {
if inviteToAccept.playerGroup == 0 || inviteToAccept.playerGroup == myPlayerGroup {
inviteAccepted()
}
else {
// TO SOMETHING
myPlayerGroup = inviteToAccept.playerGroup
inviteAccepted()
}
Okay, I managed to create a match between two players. Now I will do a little test about sending data to a player.
I didn't quite get the explanation about NSData. Essentially, what is it? How do I send a, dunno, array to another player?
Apple mentioned data packets could be lost. But there was a "reliable" mode to prevent that. But I couldn't find about such.
Any ideas?
Yes, you have to make your OWN protocol. "making a protocol" is something you do yourself. Something like...Essentially on the server end
// the message arrives and you then do this...
[data getBytes:&getMe length:sizeof(CommsProt)];
whereas on the client end to send messages, you do this...
NSData * data = [NSData dataWithBytes:&sendMe length:sizeof(CommsProt)];
// ...now send that data using GameKit or whatever system you end up with
and you define your protocol - at least the chunks of data - like this:
typedef struct _CommsProt
{
BOOL happyThing;
someThings wotJustHappened;
float happyValue;
float anotherHappyValue;
// etc
}
CommsProt;
If you are new to GK, be aware of this critical tip ...
Client/Server GKSessions
This could also help...
Most effective way to do networking on Mac/iPhone?
Some helpful notes...
(i) "client" and "server" mean nothing. You will be able to send the handbags of information (such as "CommsProt" above) in either direction. If you want to think of, and refer to one, end as a server (particularly if you have a hub-type arrangement), that's fine. But it's only in your head. (By the way, commonly you might use a different data structure in each direction, that's perfectly fine.)
(ii) Regarding sockets. If you get heavily in to networking, you will have to deal with sockets and write your own sockets code. However it is very likely you can choose a networking layer where you never even have to say the word "sockets"! GameKit + Bonjour, for example, completely take care of handling sockets for you, AND that combination takes care of the other incredibly difficult issue which is FINDING one of your client/servers. If you are new I recommend you completely set aside sockets for now, and use a system such as GameKit (or whatever is equivalent on Windows) for your networking layer.
(iii) Indeed AT FIRST just use something incredibly simple like GameKit, while you figure out your protocol and all the other headaches. Later, if necessary you can rewrite the networking layer, or, switch to some other package that you hear about. Happily everything up to the code examples above will be unchanged, only the networking layer will change.
(iv) Regarding WiFi. GameKit and most convenience packages, are completely agnostic to the physical layer: they take care of it for you. GK will work fine however the phones are connected -- bluetooth, ethernet, whatever! Indeed you "won't know" what physical layer is being used. (It's sometimes annoying you can't control this: let it go, users couldn't care less.)
I have an application that is set up so that if the user selects the device to be a server it creates a GKSession in server mode, and if it selects cient it create a GKSession in client mode.
Whats happening at the moment is the server is sending out the data fine, which is just a string containing the time of the server.
The problem starts however, when I have one client already connected to the server and I then connect another client .. the problem is: the second connected client connects also to the first client for some reason.
I want to be able to not connect to other clients and just connect to the server. Any help would be great
You've hit the nail on the head:
Strangely enough, GK allows an "any to any" model.
This is a truly impressive achievement, technologically, by Apple
BUT !!! ........it is very important to realise that this is a very unusual option. In networking - for games - you almost always want a "normal" client-server model.
Over some 30 years, a huge amount of science has become established, regarding doing networking using a normal client-server "spoke" model. And indeed, for game programming, 99% of the time you definitely need, and want, a standard client-server "spoke" model.
This bears repeating:
(1) Apple created a highly unusual "peer to peer" mode when they made GK.
(2) That is technologically astounding, but,
(3) this novel P2P technology would not, actually, be used in very typical networking programming for games.
(4) Very confusingly: all the documentation talks about the P2P mode. This is confusing because: if you are new to networking programming, it would make you think that is "normal". In fact, it is very likely you will never use the P2P mode at all, when making real normal games.
To repeat!
If you are new to networking, when you see all the mentions of P2P mode in Apple's doco, it's important to realise that the (amazing) P2P feature is more of a novelty. In fact, for essentially all game networking, you will definitely need normal "everyday" client-server "spoke style" networking.
Just to ne crystal-clear .. it is much, much, much !! easier to do real-life networking using a normal client-server "spoke" model.
The P2P mode is "really clever" and you could definitely spend some time experimenting with it. For instance, it is fine for just "sending chat around" to every device connected.
But again (if you're a new networking programmer) you should realise it is rather a novelty. You will have to program using a normal, everyday, client-server model.
So ......................
given that you are going to program in a normal everyday client-server model.
Your first job becomes, strangely enough, "disabling" the P2P aspect!!!!!
This is easy enough if you know how. Here's precisely how to do it...
sessionMode:GKSessionModeServer .. on the server.
sessionMode:GKSessionModeClient .. on the client.
So, for normal client-server programming, don't use GKSessionModePeer anywhere.
Secondly, don't forget in your clients, simply do not implement didReceiveConnectionRequestFromPeer:
Finally if all that doesn't work! In your clients, in peer:didChangeState:, you need to do this ...
// so this is in the CLIENT...
-(void)session:(GKSession *)session peer:(NSString *)peerID
didChangeState:(GKPeerConnectionState)state
{
switch (state)
{
case GKPeerStateAvailable:
// you have found the server!!
// [session displayNameForPeer:peerID]
self.theServerWeAreConnectedToPeerID = peerID;
// you will definitely need to save that
[session connectToPeer:theServerWeAreConnectedToPeerID
withTimeout:0];
break;
case GKPeerStateConnected:
// MAKE SURE it's our server
// not just some bizarre peers, etc etc.
if ( [theServerWeAreConnectedToPeerID isEqualToString:peerID] )
{
// you are connected - launch your tick or whatever
}
else
{
// completely ignore this!
}
break;
case GKPeerStateDisconnected:
if ( [theServerWeAreConnectedToPeerID isEqualToString:peerID] )
{
// you have been disconnected from the server!!
}
else
{
// weirdly this is telling you that one of your sister
// clients, has been disconnected from the server. IGNORE
}
break;
// GKPeerStateUnavailable .. likely not relevant
case GKPeerStateUnavailable:
// do nothing, ignore
break;
// from the modern doco..
// "The delegate should ignore GKPeerStateConnecting changes
// and implement the session:didReceiveConnectionRequestFromPeer:
// method instead." .. blah blah .. for us that comment only
// applies TO OUR SERVER, NOT here in the client.
case GKPeerStateConnecting:
// do nothing, ignore
break;
}
}
Just to repeat. It is very likely you will want to NOT-use the P2P model: so, all of the above explains "how to DISABLE the P2P stuff."
Once again to repeat for absolute clarity:
GK (surpriginsly) contains a P2P mode. This is technologically amazing. You can, of course, use P2P mode for simple networking problems (notably chat-like problems). In practice, all the typical networking needs of any real game (whether an FPS, sports game, or whatever) must be done in ordinary client-server paradigm. (It would be staggeringly difficult to use P2P mode.)
Thus, it's necessary as a "first step" to know how to "not use" the P2P system in GK -- that is explained above in length.
(If you DO want to use the P2P system - you're all set, go for it !!)
GK is fantastic if you can figure out all the subtleties. With GK and ASIHttpRequest, you can basically do anything between computers at least in a basic way.
This question has hit the nail on the head ........ GK has a (highly unusual) P2P mode, and the documentation focusses on the P2P mode, which can be confusing to newcomers. Again P2P is incredibly clever, but as a rule you do not want the P2P mode. You want a normal clients-with-server spoke model, which is incedibly easier to program. Hope it helps!