scripts下的super和cell文件夹可以换成controller和model
socket.io插件本地不用导入,但是1.32有bug打包到web平台没有打包原生的socket.io,所以我自己加了一个socket.io
客户端
https://github.com/potato47/reversi-online
服务端
https://github.com/potato47/reversi-online-server
所有代码
Global.js
window.G = {
globalSocket:null,//全局
hallSocket:null,//大厅
queueSocket:null,//队列
roomSocket:null,//房间
gameManager:null,
chessManager:null,
stand:null,
}
Constants.js
const STAND = cc.Enum({
BLACK: 47,
WHITE: -47
});
const CHESS_TYPE = cc.Enum({
NONE: -1,
BLACK: 47,
WHITE: -47
});
const GAME_STATE = cc.Enum({
PREPARE: -1,
PLAYING: -1,
OVER: -1
});
const DIR = cc.Enum({
LEFT:-1,
LEFT_UP:-1,
UP:-1,
RIGHT_UP:-1,
RIGHT:-1,
RIGHT_DOWN:-1,
DOWN:-1,
LEFT_DOWN:-1
});
module.exports = {
STAND:STAND,
CHESS_TYPE:CHESS_TYPE,
GAME_STATE:GAME_STATE,
DIR:DIR
};
MenuManager.js
这里写代码片cc.Class({
extends: cc.Component,
onLoad: function () {
G.globalSocket = io.connect('127.0.0.1:4747');
//断开连接后再重新连接需要加上{'force new connection': true}
G.hallSocket = io.connect('127.0.0.1:4747/hall',{'force new connection': true});
},
onBtnStart() {
G.hallSocket.disconnect();
cc.director.loadScene('match');
}
});
MatchManager.js
const Constants = require('Constants');
const STAND = Constants.STAND;
cc.Class({
extends: cc.Component,
onLoad: function () {
G.queueSocket = io.connect('127.0.0.1:4747/queue', { 'force new connection': true });
G.queueSocket.on('set stand', function (stand) {
if (stand === 'black') {
G.stand = STAND.BLACK;
} else if (stand === 'white') {
G.stand = STAND.WHITE;
}
});
G.queueSocket.on('match success', function (roomId) {
cc.log('match success' + roomId);
G.roomSocket = io.connect('127.0.0.1:4747/rooms' + roomId, { 'force new connection': true });
G.queueSocket.disconnect();
cc.director.loadScene('game');
});
},
onBtnCancel() {
G.queueSocket.disconnect();
cc.director.loadScene('menu');
}
});
GameManager.js
const Constants = require('Constants');
const GAME_STATE = Constants.GAME_STATE;
const STAND = Constants.STAND;
const CHESS_TYPE = Constants.CHESS_TYPE;
cc.Class({
extends: cc.Component,
properties: {
gameState: {
default: GAME_STATE.PREPARE,
type: GAME_STATE
},
turn: {
default: STAND.BLACK,
type: STAND
},
blackScoreLabel: cc.Label,
whiteScoreLabel: cc.Label,
infoPanel: cc.Node,
infoLabel: cc.Label
},
// use this for initialization
onLoad: function () {
G.gameManager = this;
this.infoAnimation = this.infoPanel.getComponent(cc.Animation);
},
startGame() {
this.turn = STAND.BLACK;
this.gameState = GAME_STATE.PLAYING;
this.showInfo('start game');
},
endGame() {
let onFinished = () =>{
G.roomSocket.disconnect();
cc.director.loadScene('menu');
}
this.infoAnimation.on('finished',onFinished,this);
this.gameState = GAME_STATE.OVER;
this.showInfo('game over');
},
changeTurn() {
if (this.turn === STAND.BLACK) {
this.turn = STAND.WHITE;
} else if (this.turn === STAND.WHITE) {
this.turn = STAND.BLACK;
}
},
forceChangeTurn() {//无子可下换边
this.showInfo('force change turn');
this.changeTurn();
},
updateScore() {
let chessCount = G.chessManager.getChessCount();
let blackChess = chessCount[0];
let whiteChess = chessCount[1];
this.blackScoreLabel.string = blackChess + '';
this.whiteScoreLabel.string = whiteChess + '';
},
showInfo(type) {
let chessCount = G.chessManager.getChessCount();
let blackChess = chessCount[0];
let whiteChess = chessCount[1];
if (type === 'start game') {
if (G.stand === STAND.BLACK) {
this.infoLabel.string = '你是蓝色方\n执黑棋先手';
} else if (G.stand === STAND.WHITE) {
this.infoLabel.string = '你是红色方\n执白棋后手';
}
} else if (type === 'game over') {
if (blackChess > whiteChess) {
this.infoLabel.string = '游戏结束\n黑棋胜';
} else if (blackChess < whiteChess) {
this.infoLabel.string = '游戏结束\n白棋胜';
} else if (blackChess === whiteChess) {
this.infoLabel.string = '游戏结束\n平局';
}
} else if (type === 'force change turn') {
if (G.stand === STAND.BLACK) {
this.infoLabel.string = '黑方无子可下\n请白方下子';
} else if (G.stand === STAND.WHITE) {
this.infoLabel.string = '白方无子可下\n请黑方下子';
}
}
this.infoAnimation.play();
}
});
ChessManager.js
const Constants = require('Constants');
const CHESS_TYPE = Constants.CHESS_TYPE;
const STAND = Constants.STAND;
const GAME_STATE = Constants.GAME_STATE;
cc.Class({
extends: cc.Component,
properties: {
COL: 8,
ROW: 8,
chessPrefab: cc.Prefab,
chesses: []
},
// use this for initialization
onLoad: function () {
G.chessManager = this;
this.chessWidth = this.node.width / this.COL;
for (let x = 0; x < this.COL; x++) {
this.chesses[x] = [];
for (let y = 0; y < this.ROW; y++) {
let chessNode = cc.instantiate(this.chessPrefab);
chessNode.parent = this.node;
chessNode.width = this.chessWidth - 5;
chessNode.height = this.chessWidth - 5;
chessNode.position = cc.p(this.chessWidth / 2 + x * this.chessWidth, this.chessWidth / 2 + y * this.chessWidth);
let chess = chessNode.getComponent('Chess');
chess.coor = cc.p(x, y);
this.chesses[x][y] = chess;
this.addTouchEvent(chess);
}
}
this.chesses[3][3].type = CHESS_TYPE.BLACK;
this.chesses[3][4].type = CHESS_TYPE.WHITE;
this.chesses[4][4].type = CHESS_TYPE.BLACK;
this.chesses[4][3].type = CHESS_TYPE.WHITE;
G.gameManager.startGame();
let self = this;
G.roomSocket.on('update chessboard', function (chessCoor) {
self.fallChess(self.chesses[chessCoor.x][chessCoor.y]);
});
G.roomSocket.on('change turn', function () {
G.gameManager.changeTurn();
});
G.roomSocket.on('force change turn', function () {
G.gameManager.forceChangeTurn();
});
},
addTouchEvent(chess) {
let self = this;
chess.node.on('touchend', function (e) {
if (G.gameManager.gameState === GAME_STATE.PLAYING && G.gameManager.turn === G.stand) {
if (chess.type === CHESS_TYPE.NONE) {
for (let dir = 1; dir <= 8; dir++) {
if (self.judgePass(G.gameManager.turn, chess, dir)) {
self.fallChess(chess);
G.roomSocket.emit('update chessboard', chess.coor);
break;
}
if (dir === 8) {
return;
}
}
}
}
});
},
fallChess(chess) {
if (G.gameManager.turn === STAND.BLACK) {
chess.type = CHESS_TYPE.BLACK;
} else if (G.gameManager.turn === STAND.WHITE) {
chess.type = CHESS_TYPE.WHITE;
}
for (let dir = 1; dir <= 8; dir++) {
if (this.judgePass(G.gameManager.turn, chess, dir)) {
this.changePass(chess, dir);
}
}
G.gameManager.updateScore();
G.gameManager.changeTurn();
this.judgeWin();
},
nearChess(chess, dir) {
switch (dir) {
case 1://left
if (chess.coor.x !== 0) {
return this.chesses[chess.coor.x - 1][chess.coor.y];
}
break;
case 2://left up
if (chess.coor.x !== 0 && chess.coor.y !== this.ROW - 1) {
return this.chesses[chess.coor.x - 1][chess.coor.y + 1];
}
break;
case 3://up
if (chess.coor.y !== this.ROW - 1) {
return this.chesses[chess.coor.x][chess.coor.y + 1];
}
break;
case 4://right up
if (chess.coor.x !== this.COL - 1 && chess.coor.y !== this.ROW - 1) {
return this.chesses[chess.coor.x + 1][chess.coor.y + 1];
}
break;
case 5://right
if (chess.coor.x !== this.COL - 1) {
return this.chesses[chess.coor.x + 1][chess.coor.y];
}
break;
case 6://right down
if (chess.coor.x !== this.COL - 1 && chess.coor.y !== 0) {
return this.chesses[chess.coor.x + 1][chess.coor.y - 1];
}
break;
case 7://down
if (chess.coor.y !== 0) {
return this.chesses[chess.coor.x][chess.coor.y - 1];
}
break;
case 8://left down
if (chess.coor.x !== 0 && chess.coor.y !== 0) {
return this.chesses[chess.coor.x - 1][chess.coor.y - 1];
}
break;
default:
break;
}
return null;
},
judgePass(stand, chess, dir) {
let tempChess = chess;
tempChess = this.nearChess(chess, dir);
if (tempChess === null) {
return false;
}
while (tempChess.type === -stand) {
tempChess = this.nearChess(tempChess, dir);
if (tempChess === null) {
return false;
}
if (tempChess.type == stand) {
return true;
}
}
return false;
},
changePass(chess, dir) {
let tempChess = this.nearChess(chess, dir);
while (tempChess.type === -G.gameManager.turn) {
tempChess.type = chess.type;
tempChess = this.nearChess(tempChess, dir);
}
},
judgeMoveAble(stand) {//判断stand是否有可落子的地方
let tryChess = null;
for (let x = 0; x < this.COL; x++) {
for (let y = 0; y < this.ROW; y++) {
tryChess = this.chesses[x][y];
if (tryChess.type === CHESS_TYPE.NONE) {
for (let dir = 1; dir <= 8; dir++) {
if (this.judgePass(stand, tryChess, dir)) {
return true;
}
}
}
}
}
return false;
},
judgeWin() {
let selfMoveAble = this.judgeMoveAble(G.gameManager.turn);
let oppoMoveAble = this.judgeMoveAble(-G.gameManager.trun);
if (selfMoveAble) {
return;
} else if (!selfMoveAble && oppoMoveAble) {
cc.log('can not move next turn');
G.gameManager.forceChangeTurn();
G.roomSocket.emit('force change turn');
} else if (!selfMoveAble && !oppoMoveAble) {
cc.log('both can not move someone win');
G.gameManager.endGame();
}
},
getChessCount(){
let blackChess = 0;
let whiteChess = 0;
for (let x = 0; x < this.chesses.length; x++) {
for (let y = 0; y < this.chesses[x].length; y++) {
if (this.chesses[x][y].type === CHESS_TYPE.BLACK) {
blackChess++;
} else if (this.chesses[x][y].type === CHESS_TYPE.WHITE) {
whiteChess++;
}
}
}
return [blackChess,whiteChess];
}
});
Chess.js
const Constants = require('Constants');
const CHESS_TYPE = Constants.CHESS_TYPE;
cc.Class({
extends: cc.Component,
properties: {
pics:{
default:[],
type:[cc.SpriteFrame]
},
_type:CHESS_TYPE.NONE,
type:{
get(){
return this._type;
},
set(value){
this._type = value;
if(value === CHESS_TYPE.BLACK){
this.getComponent(cc.Sprite).spriteFrame = this.pics[0];
}else if(value === CHESS_TYPE.WHITE){
this.getComponent(cc.Sprite).spriteFrame = this.pics[1];
}else{
this.getComponent(cc.Sprite).spriteFrame = null;
}
}
},
coor:cc.p(0,0),//坐标
chance:0//周围可翻转棋子的可能性
},
onLoad(){
this.type = CHESS_TYPE.NONE;
}
});
reversi-server.js
'use strict'
let app = require('express')();
let server = require('http').Server(app);
let io = require('socket.io')(server);
server.listen(4747, function() {
console.log('listening on:4747');
});
let MAX = 30;//最大支持连接房间数
let hall = null;//大厅
let queue = null;//匹配队列
let rooms = [];//游戏房间
function Hall() {
this.people = 0;
this.socket = null;
}
function Room(){
this.people = 0;
this.socket = null;
}
function Queue(){
this.people = 0;
this.socket = null;
}
hall = new Hall();
queue = new Queue();
for(let n = 0;n < MAX;n++){
rooms[n] = new Room();
}
function getFreeRoom(){
for(let n = 0;n < MAX;n++){
if(rooms[n].people === 0){
return n;
}
}
return -1;
}
io.people = 0;
io.on('connection',function(socket){
io.people++;
console.log('someone connected');
socket.on('disconnect',function(){
io.people--;
console.log('someone disconnected');
});
})
hall.socket = io.of('/hall').on('connection', function(socket) {
hall.people++;
console.log('a player connected.There are '+hall.people+' people in hall');
hall.socket.emit('people changed',hall.people);
socket.on('disconnect',function(){
hall.people--;
console.log('a player disconnected.There are '+hall.people+' people in hall');
hall.socket.emit('people changed',hall.people);
});
});
queue.socket = io.of('/queue').on('connection',function(socket){
queue.people++;
console.log('someone connect queue socket.There are '+queue.people+' people in queue');
if(queue.people === 1){
socket.emit('set stand','black');
}else if(queue.people === 2){
socket.emit('set stand','white');
let roomId = getFreeRoom();
console.log(roomId+"roomId");
if(roomId >= 0){
queue.socket.emit('match success',roomId);
console.log('match success.There are '+queue.people+' people in queue');
}else{
console.log('no free room!');
}
}
socket.on('cancel match',function(){
queue.people--;
console.log('someone cancel match.There are '+queue.people+' people in queue');
});
socket.on('disconnect',function(){
queue.people--;
console.log('someone disconnected match.There are '+queue.people+' people in queue');
});
});
for(let i = 0;i < MAX;i++){
rooms[i].socket = io.of('/rooms'+i).on('connection',function(socket){
rooms[i].people++;
console.log('some one connected room'+i+'.There are '+rooms[i].people+' people in the room');
socket.on('update chessboard',function(chessCoor){
socket.broadcast.emit('update chessboard',chessCoor);
});
socket.on('force change turn',function(){
socket.broadcast.emit('force change turn');
});
socket.on('disconnect',function(){
rooms[i].people--;
console.log('someone disconnected room'+i+'.There are '+rooms[i].people+' people in the room');
});
});
}