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