Før vi kommer ind på tråde vil jeg lige give nogle overvejelser til strukturen. Mit forslag er at Spiller (her tænker jeg på interaktionen med en fysisk spiller) og Spillet er så afkoblede fra hinanden som muligt. Det er min erfaring det gøre det nemmere.
Så det eneste en Spiller kan gøre er at lave
Ændringer til Spillet, samt aflæse den nuværende tilstand af Spillet. F.eks. kunne en Ændring være at placere en brik.
Så bliver den eneste forskel på en lokal spiller og en netværksspiller, at den ene kommunikerer gennem en GUI og den anden gennem en netværksforbindelse. Begge spiller generer Ændringer som du påvirker Spillet med.
Så måden et multiplayer spil startes på er:
1. Server "lytter" på en Socket.
2. Klient forbinder med Socket.
3.a: Server opretter en FjernSpiller med Socketen som kører i en tråd og starter så også en GUISpiller.
3.b: Client opretter en FjernSpiller med Socketen som kører i en tråd og starter så også GUISpiller.
4. Begge fortsætter nu spillet som almindelig.
Så mit forslag er at din try bliver noget lignende (har tilføjet kommentarer til nogle af de nye dele):
- try
- {
- Main.gameboard = new Gameboard();
- System.out.println("Server started");
- final int PORT = 34652;
- ServerSocket listener = new ServerSocket(PORT);
- // Wait up to 30s on a connection
- listener.setTimeout(30 * 1000)
- System.out.println("The game server is running and waiting for clients.");
- Socket client = listener.accept();
- // Close ServerSocket, we have the client Socket now.
- listener.close();
- // Create new thread that handles communication and interaction with gameboard
- new Thread(new RemotePlayer(client, PlayerRole.Cross, gameboard));
- }
- catch (SocketTimeoutException ex)
- {
- //You get here if no-one connects in time.
- }
- catch (Exception ex)
- {
- System.out.print(ex.getMessage());
- }
- // Okay launch the GUI now using this main thread.
Så skal du lave RemotePlayer som kører skal være Runnable for at blive startet i en tråd. Her er noget løst kode der viser hvordan det måske ville virke.
- class RemotePlayer implements Runnable {
- //...
- Socket client = null;
- InputStream input = null;
- OutputStream output = null;
- Gameboard game = null;
- PlayerRole role;
- public RemotePlayer(Socket client, PlayerRole role, GameBoard game) {
- this.client = client;
- this.role = role;
- this.input = client.getInputStream();
- this.output = client.getOutputStream();
- this.game = game;
- }
-
- void run() {
- // This is where the thread starts
- // You are probably gonna need a protocol for communicating.
- // Perhaps something like: first byte is how long the next part is
- // For example to the command "NAME" which indicates the name of the player on
- // the other end might be sent as: [4]Name[7]Kenneth where [X] is the raw number X not the ascii value for X.
- try {
- while (true) {
- String command = readCommand();
- if (command.equals("NAME")) {
- String remoteName = readString();
- // Update the game, you need to be careful with threads here, because of race conditions with the GUI.
- game.setOtherDudesName(remoteName);
- // Send our name back
- sendCommand("NAME");
- sendString(game.localName);
- }
- else if (command.equals("QUIT")) {
- game.setStatus(LOCAL_WIN, "Opponent quit the game!");
- client.close();
- break; //Exit the infinite loop
- }
- else if (command.equals("PLACE_PIECE")) {
- // ...
- }
- }
- } catch (Exception ex) {
- //The connection might be lost or other things you need to handle here.
- }
-
- }
-
- String readCommand() {
- int commandLength = input.read();
- // Make room for command
- byte[] data = new byte[commandLength];
- int bytesRead = 0;
- while (bytesRead < commandLength) {
- bytesRead += input.read(data, bytesRead, commandLength - bytesRead);
- }
- return new String(data, StandardCharsets.UTF_8);
- }
- String readString() {
- // Same implementation as command at the moment
- return readCommand();
- }
- }
Indlæg senest redigeret d. 31.05.2017 17:12 af Bruger #14645