使用WebSocket实现多组即时对战五子棋

https://download.csdn.net/download/xuhangsong/10579033   完整项目下载地址

 几年前写的一个webSocket实现的五子棋对战功能,这次整理下分享一下,顺便以后自己也能回忆起来。

实现很简单,就一个html,一个js,再加个websocket.java和封装的传输类就能实现一个可以对战,可以发消息的五子棋功能,那是竟然还在用jdk1.7开发。。

接下来上代码,因为代码中当时写的时候加了注释,我现在回过来看很好理解各种业务设计,给我节约了很多时间。

chess.html页面



	
		
		
		
		
		
		
	
	
		

rule.js,具体前端功能的实现都在这个js中了,棋盘背景是用canvas画的,上面盖着div块,用来落子><

var bout = false;//是否允许落子
var color = "";//自己落子颜色
var websocket = null;
var row = 15;
var col = 15;
var widthAndHeight = 30;//格子宽度高度
var WuZiQi = {
	isEnd:function(xy,chessmanColor){//判断是否结束游戏
		var id = parseInt(xy);
		//竖的计算
		var num = 1;
		num = WuZiQi.shujia(num,id,chessmanColor);
		num = WuZiQi.shujian(num,id,chessmanColor);
		if(num>=5){
			if(chessmanColor==color){
				confirm("游戏结束!你赢了!");
			}else{
				confirm("游戏结束!你输了!");
			}
			return ;
		}
		num = 1;
		num = WuZiQi.hengjia(num,id,chessmanColor);
		num = WuZiQi.hengjian(num,id,chessmanColor);
		if(num>=5){
			if(chessmanColor==color){
				confirm("游戏结束!你赢了!");
			}else{
				confirm("游戏结束!你输了!");
			}
			return ;
		}
;		num = 1;
		num = WuZiQi.zuoxiejia(num,id,chessmanColor);
		num = WuZiQi.zuoxiejian(num,id,chessmanColor);
		if(num>=5){
			if(chessmanColor==color){
				confirm("游戏结束!你赢了!");
			}else{
				confirm("游戏结束!你输了!");
			}
			return ;
		}
		num = 1;
		num = WuZiQi.youxiejia(num,id,chessmanColor);
		num = WuZiQi.youxiejian(num,id,chessmanColor);
		if(num>=5){
			if(chessmanColor==color){
				confirm("游戏结束!你赢了!");
			}else{
				confirm("游戏结束!你输了!");
			}
			return ;
		}
	},youxiejia:function(num,id,color){
		var yu = id%row;
		id = id+(row-1);
		if(id<(row*col)&&(id%row)=0&&(id%row)>yu){
			var flag = WuZiQi.checkColor(id,color);
			if(flag){
				num++;
				return WuZiQi.youxiejian(num,id,color);
			}else{
				return num;
			}
		}else{
			return num;
		}
	},zuoxiejia:function(num,id,color){
		var yu = id%row;
		id = id+(row+1);
		if(id<(row*col)&&(id%row)>yu){
			var flag = WuZiQi.checkColor(id,color);
			if(flag){
				num++;
				return WuZiQi.zuoxiejia(num,id,color);
			}else{
				return num;
			}
		}else{
			return num;
		}
	},zuoxiejian:function(num,id,color){
		var yu = id%row;
		id = id-(row+1);
		if(id>=0&&(id%row)yu){
			var flag = WuZiQi.checkColor(id,color);
			if(flag){
				num++;
				return WuZiQi.hengjia(num,id,color);
			}else{
				return num;
			}
		}else{
			return num;
		}
		
	},
	hengjian:function(num,id,color){
		var yu = id%row;
		id = id-1;
		if(id>=0&(id%row)=0){
			var flag = WuZiQi.checkColor(id,color);
			if(flag){
				num++;
				return WuZiQi.shujian(num,id,color);
			}else{
				return num;
			}
		}else{
			return num;
		}
	},
	checkColor:function(xy,color){
		if($("#"+xy).children("div").hasClass(color)){
			return true;
		}else {
			return false;
		}
	},
	playchess:function(e){
		if(bout&&color!=""){
			if($(e).children("div").length>0){
				alert("这里已经有子了!请在其它地方落子!");
				return;
			}
			var result = {};
			result.xy = $(e).attr("id");
			result.color = color;
			result.message = "系统:您已落子,请等待对手落子!";
			result.bout = false;
			if(websocket!=null){
				websocket.send(JSON.stringify(result));
			}else{
				$("#messageContent").append("系统:已断开连接");
				$("#messageContent").append("\n");
			}
		}else{
			if(color==""){
				$("#messageContent").append("系统:游戏还没有开始!");
				$("#messageContent").append("\n");
				$("#messageContent").scrollTop($("#messageContent")[0].scrollHeight - $("#messageContent").height());
			}else{
				$("#messageContent").append("系统:请等待你的对手落子!");
				$("#messageContent").append("\n");
				$("#messageContent").scrollTop($("#messageContent")[0].scrollHeight - $("#messageContent").height());
			}
		}
		
	},
	//发送消息
    sendMessage:function(){
          var message = $("#message").val();
          if(message!=""){
          	var result = {};
          	result.message = message;
          	websocket.send(JSON.stringify(result));
          	$("#message").val("");
          }else{
          	$("#messageContent").append("系统:请不要发送空信息!");
			$("#messageContent").append("\n");
			$("#messageContent").scrollTop($("#messageContent")[0].scrollHeight - $("#messageContent").height());
          }
          
      }
};
$(function(){
	//根据棋盘格子数得到棋盘大小
	$("#background").css({width:(row*widthAndHeight)+"px",height:(col*widthAndHeight)+"px"});
	//用canvas画棋盘
	var canvas = document.createElement("canvas");
//	$(canvas).attr({width:((row-1)*widthAndHeight)+"px",height:(col-1)*widthAndHeight+"px"});
//	$(canvas).css({"position":"relative","top":(widthAndHeight/2)+"px","left":(widthAndHeight/2)+"px","z-index":9999});
	$(canvas).attr({width:(row*widthAndHeight)+"px",height:col*widthAndHeight+"px"});
	$(canvas).css({position:"relative","z-index":9999});
	var cot = canvas.getContext("2d");
	cot.fillStyle = "#EAC000";
	cot.fillRect(0,0,row*widthAndHeight,col*widthAndHeight);
	cot.lineWidth = 1;
	var offset = widthAndHeight/2;
	for(var i=0;i
"; index++; } } $("#chess").empty(); $("#chess").append(str); $("#chess").css({width:(row*widthAndHeight)+"px",height:(col*widthAndHeight)+"px",position: "absolute",top:"0px",left:"0px","z-index":99999}); $(".grid").on("click",function(){ WuZiQi.playchess(this); }); $(".grid").css({width:widthAndHeight+"px",height:widthAndHeight+"px"}); //判断当前浏览器是否支持WebSocket if('WebSocket' in window){ websocket = new WebSocket("ws://"+window.location.host+"/WuZiQi/wuziqisocket"); } else{ alert('Not support websocket'); } //连接发生错误的回调方法 websocket.onerror = function(){ }; //连接成功建立的回调方法 websocket.onopen = function(event){ }; //接收到消息的回调方法(包含了聊天,落子,开始游戏) websocket.onmessage = function(){ var result = JSON.parse(event.data); if(result.message!=""){ $("#messageContent").append(result.message); $("#messageContent").append("\n"); //将多行文本滚动总是在最下方 $("#messageContent").scrollTop($("#messageContent")[0].scrollHeight - $("#messageContent").height()); } if(result.xy!=""&&result.color!=""){ $("#"+result.xy).html("
"); bout = result.bout;//落子后才改状态 WuZiQi.isEnd(result.xy,result.color); }else if(result.xy==""&&result.bout){//没有坐标且bout为true,则为对局首次开始落子 bout = result.bout; } if(result.xy==""&&result.color!=""){//没有坐标,但有颜色,则为首次赋予棋子颜色 color = result.color; } }; //连接关闭的回调方法 websocket.onclose = function(){ }; //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function(){ websocket.close(); }; //关闭连接 function closeWebSocket(){ websocket.close(); } });

java封装传输类,(用来实现发送消息和落子)

package com.weguard.websocket;
/**
 * 
 * @author xuhan
 *
 */
public class Result {
	/**
	 * 落子坐标
	 */
	private String xy;
	/**
	 * 发送消息
	 */
	private String message;
	/**
	 * 是否允许落子
	 */
	private boolean bout;
	/**
	 * 落子颜色
	 */
	private String color;
	public String getXy() {
		return xy;
	}
	public void setXy(String xy) {
		this.xy = xy;
	}
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	public boolean isBout() {
		return bout;
	}
	public void setBout(boolean bout) {
		this.bout = bout;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	
	
}

最后就是WebSocket了

package com.weguard.websocket;

import java.io.IOException;
import java.util.HashMap;

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

import net.sf.json.JSONObject;

//该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket。类似Servlet的注解mapping。无需在web.xml中配置。
@ServerEndpoint(value="/wuziqisocket") 
public class WebSocket {
  //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
  private static HashMap webSocketMap = new HashMap();
  //与某个客户端的连接会话,需要通过它来给客户端发送数据
  private Session session;
  //连上来的页面序号,用来配对对战,1与2一组,3与4一组,依次类推,奇数为黑先走,偶数为白,后走
  private static int index = 0;
  //同上,用来从hashMap中获取websocket,(我也忘记当时为啥要另外用一个mykey了,而不是直接用index来获取)
  private int mykey = 0;
   
  /**
   * 连接建立成功调用的方法
   * @param session  可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
 * @throws IOException 
   */
  @OnOpen
  public void onOpen( Session session){
      this.session = session;
      index++;
      try {
    	  Result result = new Result();
    	  if(index%2==0){
        	  WebSocket socket1 = webSocketMap.get((index-1)+"");
        	  if(socket1!=null){
        		  result.setBout(true);
        		  result.setMessage("系统:游戏开始,请您先落子!");
        		  result.setColor("black");
        		  JSONObject json1 = JSONObject.fromObject(result);
        		  socket1.sendMessage(json1.toString());
        		  //对先落子的对象发送数据结束
        		  result.setMessage("系统:游戏开始,请等待对手落子!");
        		  result.setBout(false);
        		  result.setColor("white");
            	  this.sendMessage(JSONObject.fromObject(result).toString());
            	  //对后出手的发送消息结束
        	  }else{//偶数时没有查询到与之对应的对手,则其变为奇数,成为等待匹配的人
        		  index--;
        		  result.setMessage("系统:等待玩家匹配!");
        		  this.sendMessage(JSONObject.fromObject(result).toString());
        	  }
          }else{
        	  result.setMessage("系统:等待玩家匹配!");
    		  this.sendMessage(JSONObject.fromObject(result).toString());
          }
    	  this.mykey = index;
          webSocketMap.put(mykey+"", this);     //加入map中
          System.out.println(webSocketMap.size());
	} catch (Exception e) {
		e.printStackTrace();
	}
  }
   
  /**
   * 连接关闭调用的方法
 * @throws IOException 
   */
  @OnClose
  public void onClose(){
      webSocketMap.remove(mykey+"");  //从set中删除
      try {
    	  WebSocket socket = null;
    	  if(mykey%2==0){
        	  socket = webSocketMap.get((mykey-1)+"");
          }else{
        	  socket = webSocketMap.get((mykey+1)+"");
          }
    	  if(socket!=null){
    		  Result result = new Result();
    		  result.setMessage("你的对手已离开!");
    		  socket.sendMessage(JSONObject.fromObject(result).toString());
    	  }
	} catch (Exception e) {
		e.printStackTrace();
	}
  }
  /**
   * 收到客户端消息后调用的方法
   * @param message 客户端发送过来的消息
   * @param session 可选的参数
   */
  @OnMessage
  public void onMessage(String message) {
	  System.out.println(message);
	  JSONObject json = JSONObject.fromObject(message);
	  Result result = (Result) JSONObject.toBean(json,Result.class);
      try {
    	  WebSocket socket = null;
    	  if(mykey%2==0){
        	  socket = webSocketMap.get((mykey-1)+"");
          }else{
        	  socket = webSocketMap.get((mykey+1)+"");
          }
    	  if(socket!=null){
    		  if(result.getXy()!=null&&!"".equals(result.getXy())){//有坐标表示为落子,反之则为发送信息
        		  this.sendMessage(message);
        		  result.setBout(true);//对手的bout改为true,表示接下来可以落子
        		  result.setMessage("系统:对方已落子,正在等待您落子!");
        		  socket.sendMessage(JSONObject.fromObject(result).toString());
        	  }else{//没有坐标表示为单纯的聊天
        		  Result newResult = new Result();
        		  newResult.setMessage("自己:"+result.getMessage());
        		  this.sendMessage(JSONObject.fromObject(newResult).toString());
        		  newResult.setMessage("对方:"+result.getMessage());
        		  socket.sendMessage(JSONObject.fromObject(newResult).toString());
        	  }
    	  }
    	  
    	  
	} catch (Exception e) {
		e.printStackTrace();
	}
  }
   
  /**
   * 发生错误时调用
   * @param session
   * @param error
   */
  @OnError
  public void onError(Session session, Throwable error){
      System.out.println("连接断开");
//      error.printStackTrace();
  }
  /**
   * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
   * @param message
   * @throws IOException
   */
  public void sendMessage(String message) throws IOException{
      this.session.getBasicRemote().sendText(message);
      //this.session.getAsyncRemote().sendText(message);
  }
}

 

整个五子棋的功能就在上面了,只要放进目录中,就能正常的运行起来,具体的实现代码里都有注释。有什么见解大家一起讨论下啊

你可能感兴趣的:(使用WebSocket实现多组即时对战五子棋)