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[];
let whiteChess = chessCount[];
this.blackScoreLabel.string = blackChess + '';
this.whiteScoreLabel.string = whiteChess + '';
},
showInfo(type) {
let chessCount = G.chessManager.getChessCount();
let blackChess = chessCount[];
let whiteChess = chessCount[];
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: ,
ROW: ,
chessPrefab: cc.Prefab,
chesses: []
},
// use this for initialization
onLoad: function () {
G.chessManager = this;
this.chessWidth = this.node.width / this.COL;
for (let x = ; x < this.COL; x++) {
this.chesses[x] = [];
for (let y = ; y < this.ROW; y++) {
let chessNode = cc.instantiate(this.chessPrefab);
chessNode.parent = this.node;
chessNode.width = this.chessWidth - ;
chessNode.height = this.chessWidth - ;
chessNode.position = cc.p(this.chessWidth / + x * this.chessWidth, this.chessWidth / + y * this.chessWidth);
let chess = chessNode.getComponent('Chess');
chess.coor = cc.p(x, y);
this.chesses[x][y] = chess;
this.addTouchEvent(chess);
}
}
this.chesses[][].type = CHESS_TYPE.BLACK;
this.chesses[][].type = CHESS_TYPE.WHITE;
this.chesses[][].type = CHESS_TYPE.BLACK;
this.chesses[][].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 = ; dir <= ; dir++) {
if (self.judgePass(G.gameManager.turn, chess, dir)) {
self.fallChess(chess);
G.roomSocket.emit('update chessboard', chess.coor);
break;
}
if (dir === ) {
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 = ; dir <= ; 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 ://left
if (chess.coor.x !== ) {
return this.chesses[chess.coor.x - ][chess.coor.y];
}
break;
case ://left up
if (chess.coor.x !== && chess.coor.y !== this.ROW - ) {
return this.chesses[chess.coor.x - ][chess.coor.y + ];
}
break;
case ://up
if (chess.coor.y !== this.ROW - ) {
return this.chesses[chess.coor.x][chess.coor.y + ];
}
break;
case ://right up
if (chess.coor.x !== this.COL - && chess.coor.y !== this.ROW - ) {
return this.chesses[chess.coor.x + ][chess.coor.y + ];
}
break;
case ://right
if (chess.coor.x !== this.COL - ) {
return this.chesses[chess.coor.x + ][chess.coor.y];
}
break;
case ://right down
if (chess.coor.x !== this.COL - && chess.coor.y !== ) {
return this.chesses[chess.coor.x + ][chess.coor.y - ];
}
break;
case ://down
if (chess.coor.y !== ) {
return this.chesses[chess.coor.x][chess.coor.y - ];
}
break;
case ://left down
if (chess.coor.x !== && chess.coor.y !== ) {
return this.chesses[chess.coor.x - ][chess.coor.y - ];
}
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 = ; x < this.COL; x++) {
for (let y = ; y < this.ROW; y++) {
tryChess = this.chesses[x][y];
if (tryChess.type === CHESS_TYPE.NONE) {
for (let dir = ; dir <= ; 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 = ;
let whiteChess = ;
for (let x = ; x < this.chesses.length; x++) {
for (let y = ; 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[];
}else if(value === CHESS_TYPE.WHITE){
this.getComponent(cc.Sprite).spriteFrame = this.pics[];
}else{
this.getComponent(cc.Sprite).spriteFrame = null;
}
}
},
coor:cc.p(,),//坐标
chance://周圍可翻轉棋子的可能性
},
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(, function() {
console.log('listening on:4747');
});
let MAX = ;//最大支援連接配接房間數
let hall = null;//大廳
let queue = null;//比對隊列
let rooms = [];//遊戲房間
function Hall() {
this.people = ;
this.socket = null;
}
function Room(){
this.people = ;
this.socket = null;
}
function Queue(){
this.people = ;
this.socket = null;
}
hall = new Hall();
queue = new Queue();
for(let n = ;n < MAX;n++){
rooms[n] = new Room();
}
function getFreeRoom(){
for(let n = ;n < MAX;n++){
if(rooms[n].people === ){
return n;
}
}
return -;
}
io.people = ;
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 === ){
socket.emit('set stand','black');
}else if(queue.people === ){
socket.emit('set stand','white');
let roomId = getFreeRoom();
console.log(roomId+"roomId");
if(roomId >= ){
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 = ;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');
});
});
}