Search code examples
iosxcodeswiftgame-centermultiplayer

Why can't I get the devices to connect together through Game Center Multiplayer?


Im making a game that uses the GameCenter Multiplayer but Im stuck right now trying to figure out how would I make the node move on my device when I move it on my simulator and the other way around also. I got the Game Center to authenticate, find a match, Look for player, and found player but when I get to my gameplay theres no multiplayer activity between the two devices. Can someone help me with this? Sorry for all the code. Thanks!

func lookupPlayers() {
    println("Looking up \(match.playerIDs.count) players...")

    GKPlayer.loadPlayersForIdentifiers(match?.playerIDs) { (players, error) -> Void in
        if error != nil {
            println("Error retrieving player info: \(error.localizedDescription)")
            self.matchStarted = false
            self._delegate?.matchEnded()
        }
        else {
            self.playersDict = NSMutableDictionary(capacity: players.count)
            for player in players {
                println("Found player: \(player.alias)")
                self.playersDict?.setObject(player, forKey: player.playerID)
            }
        }
        self.playersDict?.setObject(GKLocalPlayer.localPlayer(), forKey: GKLocalPlayer.localPlayer().playerID)
        self.matchStarted = true
    }
}





func match(match: GKMatch!, didFailWithError error: NSError!) {
    println("error!")
}


func match(match: GKMatch!, shouldReinviteDisconnectedPlayer player: GKPlayer!) -> Bool {
    return true
}




func match(match: GKMatch!, player playerID: String!, didChangeState state: GKPlayerConnectionState) {

    println("what!")

    self.lookupPlayers()
}


func match(match: GKMatch!, player: GKPlayer!, didChangeConnectionState state: GKPlayerConnectionState) {
    println("connects or disconnects")






}

func matchmakerViewController(viewController: GKMatchmakerViewController!, didFindMatch match: GKMatch!) {

    println("match found")

    var goToMatch = GamePlay(size: self.size)
    var transitionToMatch = SKTransition.fadeWithDuration(1.0)
    goToMatch.scaleMode = SKSceneScaleMode.AspectFill
    self.scene!.view?.presentScene(goToMatch, transition: transitionToMatch)

    presentingViewController = viewController
    self.presentingViewController.dismissViewControllerAnimated(true, completion: nil)

    self.match = match
    self.match.delegate = self

    self.lookupPlayers()
}


func matchmakerViewController(viewController: GKMatchmakerViewController!, didReceiveAcceptFromHostedPlayer playerID: String!) {

}


func matchmakerViewController(viewController: GKMatchmakerViewController!, didFindPlayers playerIDs: [AnyObject]!) {

}


func matchmakerViewController(viewController: GKMatchmakerViewController!, didFailWithError error: NSError!) {

    presentingViewController = viewController
    self.presentingViewController.dismissViewControllerAnimated(true, completion: nil);
    println("Error finding match: \(error.localizedDescription)");

}


func matchmakerViewController(viewController: GKMatchmakerViewController!, didFindHostedPlayers players: [AnyObject]!) {

}



func matchmakerViewControllerWasCancelled(viewController: GKMatchmakerViewController!) {

    println("go back to main menu")

    presentingViewController = viewController
    self.presentingViewController.dismissViewControllerAnimated(true, completion: nil)



}


func findMatchPlease() {


    match = nil
    let matchRequest = GKMatchRequest()
    matchRequest.minPlayers = 2
    matchRequest.maxPlayers = 2


    let mmvc = GKMatchmakerViewController(matchRequest: matchRequest)
    mmvc.matchmakerDelegate = self
    let viewController = self.scene?.view?.window?.rootViewController
    viewController?.presentViewController(mmvc, animated: true, completion: nil)
}



 override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

    for touch in (touches as! Set<UITouch>) {

        var touch: UITouch = touches.first as! UITouch
        var location = touch.locationInNode(self)
        var node = self.nodeAtPoint(location)

        if node.name == "find" {



            findMatchPlease()




        }


    }


}

Solution

  • You might want to check out Game Center Programming Guide from Apple, especially Real-Time Matches chapter. Basically once your match is started, you can start exchanging data between players, if you wan't to move around some player object (node) so the movement is seen by other players you might want to implement similar code once player moved it's object / node:

    func sendPosition() {
        var msg = CGPointMake(0, 0) // set the position to send here
        let packet = NSData(bytes: &msg, length: sizeof(CGPoint))
    
        // Swift pre-2.0, no error handling
        var error: NSError?
        if !match.sendDataToAllPlayers(packet, withDataMode: .Unreliable error: &error) {
            // some error happened
        }
    
        // Swift 2.0:
        do {
            try match.sendDataToAllPlayers(packet, withDataMode: .Unreliable)
        }
        catch {
            // handle errors
        }
    }
    

    It will send CGPoint struct data to all players connected to the match, so on the other end you might want to implement GKMatchDelegate's method - match:didReceiveData:fromRemotePlayer:. It could look something like this:

    func match(_ match: GKMatch!, didReceiveData data: NSData!, fromRemotePlayer player: GKPlayer!) {
        if let msg = data.bytes as? CGPoint {
            // new position received, assign it to player it was received from
        }
    }
    

    You can send most of the data this way and receive and convert it back on the other end. But beware that Swift types can take up more bytes to send over network, I would suggest to create C structs for networking data to send or if you want to keep your code as Swift as possible try tuples:

    var myStruct = exampleStruct (
        SomeInt: 1,
        OtherInt: 2,
        SomeCString: (0x48, 0x45, 0x4C, 0x4C, 0x4F) // HELLO
    )
    var data = NSData(
        bytes: &myStruct,
        length: sizeof(exampleStruct)
    )