gitee地址:https://gitee.com/alen_ou/Gobang
在线对战地址:http://106.52.176.106:8099/
核心代码:
server.js
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
// var io = require('socket.io').listen(1314);
var userNum = 0; //记录在线人数
// var role=true;//用来分配下棋人角色 true:白旗;false:黑旗
var onlineUser = {}; //存储在线人的信息
io.on('connection', function(socket) {
let name = "";
socket.on('login', function(obj) {
onlineUser[socket.id] = obj;
//谁来的跟谁分配权限 下黑旗,白旗还是观战
userNum++;
if (userNum == 1) {
onlineUser[socket.id] = Object.assign(obj, { role: false });
} else if (userNum == 2) {
onlineUser[socket.id] = Object.assign(obj, { role: true });
} else if (userNum > 2) {
onlineUser[socket.id] = obj;
}
var player = 0;
var playRole = null;
for (let key in onlineUser) {
var user = onlineUser[key];
// console.log("用户信息", user);
if (user.hasOwnProperty("role")) {
player++;
playRole = user.role;
// console.log("playRole=" + playRole);
}
}
if (player < 2 && userNum >= 2) {
console.log(1111)
onlineUser[socket.id] = Object.assign(obj, { role: !playRole });
}
name = obj.username;
io.to(socket.id).emit('role', onlineUser[socket.id]); //将身份信息(下黑旗还是白旗)传过去
io.emit('online', onlineUser); //将在线人员名单带过去
io.sockets.emit("systemMsg", { msg: "欢迎【" + name + "】加入群聊", type: 1 });
// console.log(obj.username, 'is loginning');
// console.log('在线用户', onlineUser);
})
socket.on('disconnect', function() {
// console.log(socket.id, 'disconnected');
var flag = null;
if (onlineUser.hasOwnProperty(socket.id)) { //disconnect的时候,将它从onlineUser里删掉
var user = onlineUser[socket.id];
if (user.hasOwnProperty("role")) {
flag = user.role;
}
delete onlineUser[socket.id];
userNum--;
}
//若退出的用户是棋手角色,则判断是否还有用户没有角色,有则随机分配给没有角色的用户
var player = null;
for (let key in onlineUser) {
if (!onlineUser[key].hasOwnProperty('role')) {
onlineUser[key]['role'] = flag
}
}
//用来同步数据在线人数
io.emit('online', onlineUser);
if (name !== "" && name !== null) {
io.emit("systemMsg", { msg: "用户【" + name + "】离开群聊", type: 0 });
}
//console.log('在线用户', onlineUser, '在线人数', userNum);
});
//聊天
socket.on('chat', function(msg) {
// 参数为下到什么坐标和目前是黑方or白方
console.log(name + ":" + msg);
// console.log(msg.player?'黑方':'白方','落子在: ' + msg.place);
io.sockets.emit('chat', { name, msg });
});
//下棋
socket.on("playChess", function(msg) {
// console.log(msg.player ? '黑方' : '白方', '落子在: ' + msg.place);
io.emit('playChess', msg);
});
socket.on('reset', function(msg) {
//参数为目前黑旗or白旗
// console.log('清除重来');
io.emit('reset', msg);
});
});
http.listen(1314, function() {
console.log('listening on :1314');
});
前端核心代码:
import React from "react";
import Header from '../component/Header'
// import Control from '../component/Control'
import isSuccess from '../util/FiveSuccess'
import { message, Modal } from 'antd'
import common from '../util/common'
import io from 'socket.io-client';
var socket = io.connect('http://localhost:1314');
const getUsers = (users) => {
var userArry = []
var playerArry = []
for (let key in users) {
if (users[key].hasOwnProperty('role')) {
playerArry.push(users[key]);
}
userArry.push(users[key]);
}
return {
user: userArry,
player: playerArry
};
}
export default class Gobang extends React.Component {
constructor() {
super();
this.state = this.initStart();
}
//初始化
initStart() {
var boardData = [];
//棋盘大小
for (var i = 0; i < 15; i++) {
boardData.push(Array(15).fill(0));
}
this.history = [];
return {
//棋盘数据
boardData,
//胜负是否已分
success: false,
//是否黑子
isBlack: false,
currentUser: {},
username: "",
users: [],//登录用户
sysmsg: [],//系统消息
messages: []//聊天消息
}
}
//悔棋
unDo() {
// console.log(this.history);
// console.log(this.history.pop())
if (this.history.length === 0) {
message.warn("没有棋子了")
return
}
this.setState(this.history.pop())
}
//重新开始
reStart() {
socket.emit("reset","重新开始")
// var boardData = [];
// //棋盘大小
// for (var i = 0; i < 15; i++) {
// boardData.push(Array(15).fill(0));
// }
// this.setState({
// //棋盘数据
// boardData,
// //胜负是否已分
// success: false,
// //是否黑子
// isBlack: false,
// })
}
//登录
login(value) {
//var value = e.target.value;
if (!common.isChina(value)) {
message.error("昵称必须包含中文");
return;
}
socket.emit("login", { "username": value });
// var _this = this;
this.setState({
username: value
})
this.socketOn();
}
//聊天
sendMsg(inpVal) {
// var _this = this;
// const inpVal = this.input.value;
if (inpVal === "") {
message.error("不能发送空消息")
return;
}
socket.emit("chat", inpVal);
}
//监听
socketOn() {
var _this = this;
//监听 更新在线人数据
socket.on("online", function (res) {
_this.setState({
users: res
})
})
//监听系统广播消息,主要提示用户有谁加入群聊了
socket.on("systemMsg", function (res) {
// console.log(res);
var messages = [];
var index = 0;
if (_this.state.sysmsg.length > 0) {
index = _this.state.sysmsg.length + 1;
_this.state.sysmsg.map((item, idx) => {
messages.push(item);
})
}
if (res.type === 0) {
messages.push(<div key={index} className="sys-msg" style={{ color: 'red' }}>{new Date().toLocaleString() + " " + res.msg}</div>);
} else {
messages.push(<div key={index} className="sys-msg">{new Date().toLocaleString() + " " + res.msg}</div>);
}
//_this.state.sysmsg.push()
_this.setState({
sysmsg: messages
})
})
//监听 广播聊天消息
socket.on("chat", function (res) {
var messages = []
var index = 0;
if (_this.state.messages.length > 0) {
index = _this.state.messages.length + 1;
_this.state.messages.map((item, idx) => {
messages.push(item);
})
}
console.log(res)
if (res.name == _this.state.username) {
messages.push(<div key={index} className="rightd">
<span className="rightd_h">
{res.name}
</span>
<div className="speech right">
{res.msg}
</div>
</div>)
} else {
messages.push(
<div key={index} className="leftd">
<span className="leftd_h">
{res.name}
</span>
<div className="speech left">
{res.msg}
</div>
</div>
)
}
// console.log(messages);
_this.setState({
messages: messages
})
})
//监听下棋
socket.on("playChess", function (res) {
const { boardData } = _this.state; //isBlack, success
_this.history.push(JSON.parse(JSON.stringify(_this.state)));
var row = res.place.row;
var col = res.place.col;
var isBlack = res.place.isBlack;
boardData[row][col] = !isBlack ? 1 : 2;
var isFiveSuccess = isSuccess(boardData, row, col);
_this.setState({
boardData,
isBlack: !isBlack,
success: isFiveSuccess
})
})
//监听,重新开始
socket.on("reset", (res) => {
var boardData = [];
//棋盘大小
for (var i = 0; i < 15; i++) {
boardData.push(Array(15).fill(0));
}
_this.setState({
//棋盘数据
boardData,
//胜负是否已分
success: false,
//是否黑子
isBlack: false,
})
})
}
componentWillUnmount() {
// 卸载异步操作设置状态
clearTimeout(this.timeouter)
this.setState = (state, callback) => {
return
}
}
componentDidUpdate() {
if (this.state.success) {
Modal.success({
// icon: <ExclamationCircleOutlined/>,
content: `恭喜【${this.state.isBlack ? '白棋' : '黑棋'}】获得游戏胜利`,
// cancelText: "取消",
okText: "确定",
// onOk() {
// console.log('OK');
// },
// onCancel() {
// console.log('Cancel');
// },
});
}
}
//下棋
playPress(row, col) {
if (this.state.username === "") {
message.warn("来者何人?还不速速报上名来!");
return;
}
//判断是否有下棋权限
var user = this.state.users[socket.id];
if (user.username === this.state.username && !user.hasOwnProperty("role")) {
message.warn("你只能观战!");
return;
}
//判断黑白棋手是否都在线,若没有则不能下棋了
var users = getUsers(this.state.users);
if (users.player.length < 2) {
message.warn("没有对手,胜之无趣!");
return;
}
//判断是否该当前用户下
if (user.role !== this.state.isBlack) {
message.warn("猴急啥,还没到你呢!");
return;
}
const { success } = this.state;//boardData, isBlack,
if (success) {
message.warn("本局已结束,请开始下一局");
return;
}
//socket
var dd = {
place: {
row,
col,
isBlack: user.role
},
player: socket.id
}
socket.emit("playChess", dd)
// console.log(this.history);
// boardData[row][col]=!isBlack?1:2;
// var isFiveSuccess = isSuccess(boardData,row,col);
// this.setState({
// boardData,
// isBlack:!isBlack,
// success:isFiveSuccess
// })
}
render() {
// console.log(this.history);
return (
<div>
<Header
history={this.history}
unDo={this.unDo.bind(this)}
reStart={this.reStart.bind(this)}
isBlack={this.state.isBlack}
username={this.state.username}
users={this.state.users}
messages={this.state.messages}
sysmsg={this.state.sysmsg}
login={this.login.bind(this)}
sendMsg={this.sendMsg.bind(this)}
boardData={this.state.boardData}
playPress={this.playPress.bind(this)}
/>
{/* <Control boardData={this.state.boardData} playPress={this.playPress.bind(this)}/> */}
</div>
)
}
}
注意:前后端的socket版本必须一致!!!