websocket简单实现五子棋即时对战功能

简介: 几年前做的一个小demo,代码比较老,先上下html显示效果图因为代码中注释比较详细,所以就直接上代码了html代码,也就是上图展示的效果页面DOCTYPE html> ...

几年前做的一个小demo,代码比较老,先上下html显示效果图

因为代码中注释比较详细,所以就直接上代码了

html代码,也就是上图展示的效果页面

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script type="text/javascript" src="../js/jquery-1.12.3.min.js" ></script>
        <script type="text/javascript" src="../js/json2.js" ></script>
        <script type="text/javascript" src="../js/rule.js" ></script>
        <style type="text/css">
            #background{
                position: relative;
                margin: 20px auto;
                /*background: #EAC000;*/
            }
            .chessman{
                border-radius: 15px;
                width: 30px;
                height: 30px;
                margin: 0 auto;
            }
            .white{
                background-color:white ;
            }
            .black{
                background-color: black;
            }
            .grid,.b_grid{
                float: left;
            }
            .message{
                width: 320px;
                height: 100px;
                margin: 0 auto;
            }
            #messageContent{
                width: 320px;
                height: 80px;
            }
        </style>
    </head>
    <body>
        <div id="background">
            <!--<div id="back_grid"></div>-->
            <div id="chess"></div>
        </div>
        <div class="message">
            <textarea id="messageContent" disabled="disabled" readonly="readonly"></textarea>
            <div><input id="message"/> <button onclick="WuZiQi.sendMessage()">发送</button></div>
        </div>
    </body>
</html>
chess.html

 

接下来是页面rule.js功能代码

 

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)<yu){
            var flag = WuZiQi.checkColor(id,color);
            if(flag){
                num++;
                return WuZiQi.youxiejia(num,id,color);
            }else{
                return num;
            }
        }else{
            return num;
        }
    },youxiejian: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.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.zuoxiejian(num,id,color);
            }else{
                return num;
            }
        }else{
            return num;
        }
    },
    hengjia:function(num,id,color){
        var yu = id%row;
        id = id+1;
        if(id<(row*col)&&(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)<yu){
            var flag = WuZiQi.checkColor(id,color);
            if(flag){
                num++;
                return WuZiQi.hengjian(num,id,color);
            }else{
                return num;
            }
        }else{
            return num;
        }
    },
    shujia:function(num,id,color){
        id = id+row;
        if(id<(row*col)){
            var flag = WuZiQi.checkColor(id,color);
            if(flag){
                num++;
                return WuZiQi.shujia(num,id,color);
            }else{
                return num;
            }
        }else{
            return num;
        }
    },
    shujian:function(num,id,color){
        id = id-row;
        if(id>=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<row;i++){//面板大小和棋盘一致,但格子线条比棋盘的行列少1
        cot.moveTo((widthAndHeight*i)+offset,0+offset);
        cot.lineTo((widthAndHeight*i)+offset,(col*widthAndHeight)-offset);
    }
    for(var j=0;j<col;j++){
        cot.moveTo(0+offset,(widthAndHeight*j)+offset);
        cot.lineTo((widthAndHeight*row)-offset,(j*widthAndHeight)+offset);
    }    
    cot.stroke();
    $("#background").prepend(canvas);
    //生成格子横线
//    var b_str="";
//    for(var i=0;i<(row-1);i++){
//        for(var j=0;j<(col-1);j++){
//            b_str+="<div class='b_grid'></div>";
//        }
//    }
//    $("#back_grid").append(b_str);
//    $("#back_grid").css({width:((row-1)*widthAndHeight)+"px",height:(col-1)*widthAndHeight+"px",position: "absolute",top:(widthAndHeight/2)+"px",left:(widthAndHeight/2)+"px",border:"solid 1px black"});
//    //减去线的宽度
//    $(".b_grid").css({width:(widthAndHeight-2)+"px",height:(widthAndHeight-2)+"px",border:"solid 1px black"});
    //生成落子格子
    var str="";
    var index = 0;
    for(var i=0;i<row;i++){
        for(var j=0;j<col;j++){
            str+="<div class='grid' id=\""+index+"\"></div>";
            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("<div class=\"chessman "+result.color+"\"></div>");
            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();
      }
});
rule.js

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;
    }
    
    
}
Result.java

 

最后是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<String,WebSocket> webSocketMap = new HashMap<String,WebSocket>();
  //与某个客户端的连接会话,需要通过它来给客户端发送数据
  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.java

只需要上面的4个代码,当然jquery,json2这些依然还是需要的,同学们新建一个

相关文章
|
7月前
使用uniapp实现websocket聊天功能
使用uniapp实现websocket聊天功能
|
2月前
|
前端开发 JavaScript UED
探索Python Django中的WebSocket集成:为前后端分离应用添加实时通信功能
通过在Django项目中集成Channels和WebSocket,我们能够为前后端分离的应用添加实时通信功能,实现诸如在线聊天、实时数据更新等交互式场景。这不仅增强了应用的功能性,也提升了用户体验。随着实时Web应用的日益普及,掌握Django Channels和WebSocket的集成将为开发者开启新的可能性,推动Web应用的发展迈向更高层次的实时性和交互性。
82 1
|
4月前
|
Linux C++ Docker
【Azure 应用服务】App Service for Linux 中实现 WebSocket 功能 (Python SocketIO)
【Azure 应用服务】App Service for Linux 中实现 WebSocket 功能 (Python SocketIO)
|
5月前
|
前端开发 JavaScript API
探索Python Django中的WebSocket集成:为前后端分离应用添加实时通信功能
【7月更文挑战第17天】现代Web开发趋势中,前后端分离配合WebSocket满足实时通信需求。Django Channels扩展了Django,支持WebSocket连接和异步功能。通过安装Channels、配置设置、定义路由和消费者,能在Django中实现WebSocket交互。前端使用WebSocket API连接后端,实现双向数据流,如在线聊天功能。集成Channels提升Web应用的实时性和用户体验,适应实时交互场景的需求。**
203 6
|
4月前
|
JavaScript 前端开发 网络协议
WebSocket在Java Spring Boot+Vue框架中实现消息推送功能
在现代Web应用中,实时消息提醒是一项非常重要的功能,能够极大地提升用户体验。WebSocket作为一种在单个TCP连接上进行全双工通信的协议,为实现实时消息提醒提供了高效且低延迟的解决方案。本文将详细介绍如何在Java Spring Boot后端和Vue前端框架中利用WebSocket实现消息提醒功能。
184 0
|
7月前
|
前端开发
t-io websocket的聊天功能学习记录(二)
t-io websocket的聊天功能学习记录(二)
99 0
|
7月前
t-io websocket的聊天功能学习记录(一)
t-io websocket的聊天功能学习记录(一)
115 0
|
移动开发 监控 网络协议
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)
|
设计模式 前端开发 Java
用WebSocket实现一个简易的群聊功能,so easy
本文主要来讲解如何使用WebSocket来实现一个简易的群聊功能。
|
前端开发 Cloud Native Java
使用Spring WebSocket实现实时通信功能
使用Spring WebSocket实现实时通信功能
107 0