Erstellen eines Echtzeit-iOS-Multiplayer-Spiels mit Swift und WebSockets (2)


Bitte beachten Sie: Dies ist Teil 2 eines 4-teiligen Tutorials. Teil 1 finden Sie hier.


Richten Sie das gemeinsam genutzte Bibliotheksprojekt ein

Das gemeinsam genutzte Bibliotheksprojekt definiert drei Objekte:

  • EIN Tile Typ, der die drei gültigen Zustände enthält, die eine Kachel haben kann: X, O oder none.
  • EIN Player Objekt, das einen Spieler im Spiel darstellt. EIN Player Objekt wird nur ein definieren id Feld- und Vergleichsmethoden.
  • EIN Message Objekt, das für die Kommunikation zwischen dem Server und dem Client bezüglich des Spielstatus verwendet wird.

Das Message, Player und Tile Objekte entsprechen alle dem Codable Protokoll, wodurch es einfach ist, in JSON zu codieren und von JSON zu decodieren.

Der Fliesentyp

Code für die Tile Art ist wirklich einfach. Wir definieren auch die Zeichenfolgen, die beim Serialisieren in JSON oder beim Decodieren des JSON zurück in eine Tile Typ.

import Foundation

public enum Tile: String, Codable {
    case none = "-"
    case x = "X"
    case o = "O"
}

Die Spielerklasse

Das Player Klasse ist etwas komplizierter. Es enthält 2 Initialisierer:

  • Ein Initialisierer zum Generieren eines neuen Spielers mit einer zufälligen ID.
  • Ein Initialisierer zum Generieren eines Players aus JSON-Daten.

Zur Generierung einer zufälligen Kennung verwenden wir a UUID.

Wir wollen in der Lage sein, a zu verwenden Player Objekt als Schlüssel in einem Wörterbuch für unser Serverprojekt. Um dies zu unterstützen, implementieren wir die Hashable Protokoll.

Zusätzlich nehmen wir a an Player einem anderen gleich sein Player sofern die Bezeichner gleich sind, wird auch die Vergleichsfunktion überschrieben. Zwei Player Objekte werden als gleich angenommen, wenn die Bezeichner gleich sind.

Das Ergebnis Player Klasse sieht dann so aus:

import Foundation

public enum PlayerError: Error {
    case creationFailed
}

public class Player: Hashable, Codable {
    public let id: String
    
    public init() {
        self.id = NSUUID().uuidString
    }
        
    public init(json: [String: Any]) throws {
        guard let id = json["id"] as? String else {
            throw PlayerError.creationFailed
        }
        
        self.id = id
    }
    
    
    
    public var hashValue: Int {
        return self.id.hashValue
    }
    
    public static func == (lhs: Player, rhs: Player) -> Bool {
        return lhs.id == rhs.id
    }
}

Die Nachrichtenklasse

Schließlich implementieren wir die Message Klasse.

Wir definieren die folgenden Kommunikationsnachrichten: join, turn, finishund stop. Eine Nachricht benötigt möglicherweise zusätzliche Daten, beispielsweise ein Spielerobjekt oder den Board-Status. Um immer richtige Nachrichten zu erstellen, fügen wir ein paar Factory-Methoden hinzu:

  • Immer wenn das Spiel gestoppt wird (z. B. wenn ein Spieler das Spiel verlassen hat), müssen wir keinen Brettstatus oder Spieler angeben. Das Spiel wird auf dem Client abgebrochen.
  • Wann immer das Spiel beendet ist, müssen wir beide den aktuellen Board-Status auf dem Client und den gewinnenden Spieler kennen oder keinen, wenn das Spiel unentschieden ist. Auf diese Weise können wir eine entsprechende Statusmeldung auf dem Client anzeigen.
  • Wann immer ein Spieler an der Reihe ist, müssen wir sowohl den aktuellen Board-Status als auch den aktiven Spieler angeben. Der Client kann dann dem aktiven Spieler erlauben zu spielen und den anderen Spieler daran hindern, einen Zug zu machen.
  • Immer wenn ein Spieler dem Server beitritt, müssen wir den Spieler angeben, damit der Server diesen Spieler zu seiner eigenen internen Spielerliste hinzufügen kann.

Das Ergebnis Message Klasse sieht wie folgt aus:

import Foundation

public enum MessageType: String, Codable {
    case join = "join"
    case turn = "turn"
    case finish = "finish"
    case stop = "stop"
}

public class Message: Codable {
    public let type: MessageType
    public let board: [Tile]?
    public let player: Player?
    
    private init(type: MessageType, board: [Tile]?, player: Player? = nil) {
        self.type = type
        self.board = board
        self.player = player
    }
    
    public static func join(player: Player) -> Message {
        return Message(type: .join, board: nil, player: player)
    }
    
    public static func stop() -> Message {
        return Message(type: .stop, board: nil)
    }
    
    public static func turn(board: [Tile], player: Player) -> Message {
        return Message(type: .turn, board: board, player: player)
    }
    
    public static func finish(board: [Tile], winningPlayer: Player?) -> Message {
        return Message(type: .finish, board: board, player: winningPlayer)
    }
}

Fahren Sie mit Teil 3 des Tutorials fort.


Similar Posts

Leave a Reply

Your email address will not be published.