Bright Java Tutorial

is brought to you by DoITBright LLC

2 Player Browser Game

Writing Your First Multiplayer Game

It is assumed that you have a background on Java, HTML5 and Javascript before going through this tutorial. Create a new Java web application project. Using your Eclipse IDE, click on "File", then click "New", the click "Java Project". Then use "MultiplayerGame" as your project name. Then, use "MultiplayerGame\WEB-INF\classes" as your default output folder. Click on the project. Then, click on "File", "New", "Package". Key-in "com.brightjavatutorial.gamedev" as the new package name. Click on that newly created package. Click "File", "New", "Class". Key-in "TwoPlayerGameServer". It will create a file "TwoPlayerGameServer.java". Below is the content of the file.

package com.brightjavatutorial.gamedev;

import java.io.IOException;
import java.util.ArrayList;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.codehaus.jackson.map.ObjectMapper;

/**
  * @author Rolan Liwanag
  */
@ServerEndpoint("/game") 
public class TwoPlayerGameServer {

  private static ArrayList sessions 
    = new ArrayList();
  private static ArrayList game_characters 
    = new ArrayList();
	
  public TwoPlayerGameServer() {
    if(game_characters.size()==0) {
      GameCharacter player1 = new GameCharacter();
      player1.color = "red";
      player1.height = 30;
      player1.width = 30;
      player1.x = 10;
      player1.y = 120;
      game_characters.add(player1);
      GameCharacter player2 = new GameCharacter();
      player2.color = "blue";
      player2.height = 30;
      player2.width = 30;
      player2.x = 300;
      player2.y = 120;
      game_characters.add(player2);
    }
  }
	
  @OnOpen
  public void onOpen(Session session){
    System.out.println(session.getId() + " has opened a connection"); 
    try {
      String guid = (String) 
        session.getRequestParameterMap().get("guid").get(0);
      sessions.add(session);
      for(GameCharacter player : game_characters) {
        if(player.sessionId==null 
            || player.sessionId.equals("")) {
          player.sessionId = session.getId();
          player.guid = guid;
          break;
        }
      }
      ObjectMapper objectMapper = new ObjectMapper();
      String message 
        = objectMapper.writeValueAsString(game_characters);
      System.out.println("\n\n" + message + "\n");
      for(Session s : sessions) {
        s.getBasicRemote().sendText(message);
      }
      System.out.println(">>> list size = " + game_characters.size());
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }
 
  @OnMessage
  public void onMessage(String message, Session session){
    try {
      for(Session s : sessions) {
        System.out.println(">>> Message to " 
          + s.getId() + " : " + message);
        s.getBasicRemote().sendText(message);
      }
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }
 
  /**
   * The user closes the connection.
   * 
   * Note: you can't send messages to the client from this method
   */
  @OnClose
  public void onClose(Session session){
    System.out.println("Session " +session.getId()+" has ended");
    try {
      for(GameCharacter player : game_characters) {
        if(player.sessionId!=null 
            && player.sessionId.equalsIgnoreCase(session.getId())) {
          player.sessionId = null;
          player.guid = null;
          break;
        }
      }
      ObjectMapper objectMapper = new ObjectMapper();
      String message 
        = objectMapper.writeValueAsString(game_characters);
      System.out.println("\n\n" + message + "\n");
      for(Session s : sessions) {
        s.getBasicRemote().sendText(message);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    sessions.remove(session);
  }
	
  class GameCharacter {
    	
    private String sessionId;
    private String guid;
    private int x;
    private int y;
    private int height;
    private int width;
    private String color;
    	
    public String getSessionId() {
	  return sessionId;
    }
    public void setSessionId(String sessionId) {
      this.sessionId = sessionId;
    }
    public String getGuid() {
      return guid;
    }
    public void setGuid(String guid) {
      this.guid = guid;
    }
    public int getX() {
      return x;
    }
    public void setX(int x) {
      this.x = x;
    }
    public int getY() {
      return y;
    }
    public void setY(int y) {
      this.y = y;
    }
    public int getHeight() {
      return height;
    }
    public void setHeight(int height) {
      this.height = height;
    }
    public int getWidth() {
      return width;
    }
    public void setWidth(int width) {
      this.width = width;
    }
    public String getColor() {
      return color;
    }
    public void setColor(String color) {
      this.color = color;
    }
  }
}
                           
You must download the javax.websocket-api-1.1.jar and place it inside your "MultiplayerGame\WEB-INF\lib" directory. If you are using Maven, below is the dependency for this.

  <dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
  </dependency>
                           
You must also download the jackson-mapper-asl-1.5.0.jar and jackson-core-asl-1.9.13.jar. If you are using Maven, below are the dependencies for these.

  <dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-mapper-asl</artifactId>
    <version>1.9.13</version>
  </dependency>
  
  <dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-core-asl</artifactId>
    <version>1.9.13</version>
  </dependency>
                           
Click on the project "MultiplayerGame". Click "File", "New", "File". Use the name "twoPlayerGameClient.html". Here is the content of the HTML5 file.

<!DOCTYPE html>
 
<html>
    <head>
        <title>Echo Chamber</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
    </head>
    <body>
       <div>
           <canvas id="myCanvas" width="400" height="300" 
             style="border:1px solid #000000;"></canvas>
       </div>
        <div>
            <input type="text" id="messageinput"/>
        </div>
        <div>
            <button type="button" onclick="openSocket();" >
              Open</button>
            <button type="button" onclick="send();" >
              Send</button>
            <button type="button" onclick="closeSocket();" >
              Close</button>
        </div>
        <!-- Server responses get written here -->
        <div id="messages"></div>
       
        <!-- Script to utilise the WebSocket -->
        <script type="text/javascript">
                       
            var webSocket;
            var messages = document.getElementById("messages");
            var canvas = document.getElementById("myCanvas");
            var ctx = canvas.getContext("2d");
            var players = [];
            var mySessionId = null;
            var myGuid = null;
           
            function openSocket(){
              // Ensures only one connection is open at a time
              if(webSocket !== undefined 
                && webSocket.readyState !== WebSocket.CLOSED){
                  //writeResponse("WebSocket is already opened.");
                  return;
              }
              //initialize guid. this will be your ID
              myGuid = guid();
              // Create a new instance of the websocket
              webSocket = new WebSocket(
                "ws://localhost:8080/MultiplayerGame/game?guid=" 
                + myGuid);
                 
              /**
               * Binds functions to the listeners for the websocket.
               */
              webSocket.onopen = function(event){
                if(event.data === undefined)
                  return;
 
                writeResponse(event.data);
              };
 
              webSocket.onmessage = function(event){
                writeResponse(event.data);
              };
 
              webSocket.onclose = function(event){
                myGuid = null;
                document.getElementById("messageinput").value 
                  = "";
                writeResponse(event.data);
              };
                
            }
           
            /**
             * Sends the value of the text input to the server
             */
            function send(){
              var text 
                = document.getElementById("messageinput").value;
              if(text != undefined 
                  && text != null && text != "") {
                webSocket.send(text);
              }
            }
           
            function closeSocket(){
              webSocket.close();
            }
 
            function writeResponse(text){
              document.getElementById("messageinput").value = text;
            }
            
            function update() {
              var text 
                = document.getElementById("messageinput").value;
              if(text) {
                players = JSON.parse(text);
              }
              send();
            }
           
            function draw() {
              ctx.clearRect(0, 0, 400, 300);
              if(players!=null) {
                for(var i=0;i<players.length;i++) {
                  ctx.fillStyle = players[i].color;
                  ctx.fillRect(players[i].x,players[i].y,
                  players[i].height,players[i].width);
                }
              }
            }
            
            function guid() {
              function s4() {
                return Math.floor((1 + Math.random()) * 0x10000)
            	  .toString(16)
            	  .substring(1);
              }
              return s4() + s4() + '-' + s4() + '-' + s4() + '-' 
            	+ s4() + '-' + s4() + s4() + s4();
            }
            
            function moveup() {
              var text 
                = document.getElementById("messageinput").value;
              if(text) {
            	players = JSON.parse(text);
            	if(players!=null) {
            	  for(var i=0;i<players.length;i++) {
            		if(players[i].guid==myGuid) {
            		  players[i].y -= 1;
                    }
            	  }
                }
                document.getElementById("messageinput").value 
                  = JSON.stringify(players);
              }
              update(); draw();
            }

            function movedown() {
              var text 
                = document.getElementById("messageinput").value;
              if(text) {
                players = JSON.parse(text);
                if(players!=null) {
                  for(var i=0;i<players.length;i++) {
                    if(players[i].guid==myGuid) {
                      players[i].y += 1;
                    }
                  }
                }
                document.getElementById("messageinput").value 
                  = JSON.stringify(players);
              }
              update(); draw();
            }

            function moveleft() {
              var text 
                = document.getElementById("messageinput").value;
              if(text) {
                players = JSON.parse(text);
                if(players!=null) {
                  for(var i=0;i<players.length;i++) {
                    if(players[i].guid==myGuid) {
                      players[i].x -= 1;
                    }
                  }
                }
                document.getElementById("messageinput").value 
                  = JSON.stringify(players);
              } 
              update(); draw();
            }

            function moveright() {
              var text 
                = document.getElementById("messageinput").value;
              if(text) {
                players = JSON.parse(text);
                if(players!=null) {
                  for(var i=0;i<players.length;i++) {
                    if(players[i].guid==myGuid) {
                      players[i].x += 1;
                    }
                  }
                }
                document.getElementById("messageinput").value 
                  = JSON.stringify(players);
              }
              update(); draw();
            }
            </script>
            <div style="text-align:center;width:480px;">
              <button onclick="moveup()">UP</button><br><br>
              <button onclick="moveleft()">LEFT</button>
              <button onclick="moveright()">RIGHT</button><br><br>
              <button onclick="movedown()">DOWN</button>
            </div>
        </script>
       
    </body>
  </html>
                           
Copy your "MultiplayerGame" directory and it's contents to you Apache Tomcat 8 webapps folder. If you are new to Apache Tomcat, the folder will be in "apache-tomcat-8.5.29\webapps". After having a copy of your directory there, start your applicationn server by going to the "apache-tomcat-8.5.29\bin" and executing the startup.sh for Unix, Linux or Mac and startup.bat for Windows. You can now explore the game via this URL.

http://localhost:8080/MultiplayerGame/twoPlayerGameClient.html

Please take not that this will only work on Apache Tomcat 8 or higher.