天天看點

【基于Cocos Creator+Socket.io的聯機對戰黑白棋(4)】——資源檔案

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');
        });

    });
}