前端实现双人联机版俄罗斯方块小游戏2(实现双人联机)

思路整理

1.游戏开始,双方都收到start消息,同时调用start方法

socket.on('start', function () {
        document.getElementById('waiting').inneHTML = '';
        start();
    });

2.start方法中,调用game.init方法,同时发送init消息给server,server收到后会转发给另一个游戏玩家

 game.init(doms, type, dir);
        socket.emit('init', {
            type: type,
            dir: dir
        });
        bindKeyEvent();
        var t = generateType();
        var d = generateDir();
        game.performNext(t, d);
        socket.emit('next', {
            type: t,
            dir: d
        })
//wsServer.js中 server收到消息
socket.on('init', function (data) {
    // 接收消息后,将其匹配给另一个socket
    if (socket.clientCount % 2 == 0) {
        socketMap[socket.clientCount - 1].emit('init', data);
    } else {
        socketMap[socket.clientCount + 1].emit('init', data);
    }
});

3.另一个游戏玩家在remote.js中接收init,会驱动对方去调用start方法(next消息同init消息)

var bindEvents = function () {
        socket.on('init', function (data) {
            // 调用start,接收init消息和传递的参数,实现两个用户相连接(在对方区域中调用了start)
            start(data.type, data.dir);
        });
        socket.on('next', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.performNext(data.type, data.dir);
        });
    }

整体代码

local.js

var Local = function (socket) {
    // 游戏对象
    var game;
    // 时间间隔 200毫秒
    var INTERVAL = 500;
    // 定时器
    var timer = null;
    // 绑定键盘事件
    // 时间计数器
    var timeConut = 0;
    var time = 0;
    var bindKeyEvent = function () {
        document.onkeydown = function (e) {
            if (e.keyCode == 38) {
                // 向上
                game.rotate();
                socket.emit("rotate");
            } else if (e.keyCode == 39) {
                // 向右
                game.right();
                socket.emit("right");
            } else if (e.keyCode == 40) {
                // 向下
                game.down();
                socket.emit("down");
            } else if (e.keyCode == 37) {
                // 向左
                game.left();
                socket.emit("left");
            } else if (e.keyCode == 32) {
                // 空格键
                game.fall();
                socket.emit("fall");
            }
        };
    };
    // 随机生成干扰行
    var generateBotLine = function (lineNum) {
        var lines = [];
        for (var i = 0; i < lineNum; i++) {
            var line = [];
            for (var j = 0; j < 10; j++) {
                line.push(Math.ceil(Math.random() * 2) - 1); // 生成 0 1 随机数
            }
            lines.push(line);
        }
        return lines;
    };
    // 移动
    var move = function () {
        timeFunc();
        // 不能下降再调用
        if (!game.down()) {
            // 落下的方块固定
            game.fixed();
            socket.emit("fixed");
            var line = game.checkClear();
            if (line) {
                // 行数不为0,则传入addScore函数
                game.addScore(line);
                socket.emit("line", line);
                if (line > 1) {
                    var bottomLines = generataBottomLines(line);
                    socket.emit('bottomLines', bottomLines);
                }
            }
            var gameOver = game.checkGameOver();
            if (gameOver) {
                game.gameOver(false);
                document.getElementById("remote_gameover").innerHTML = "你赢了";
                socket.emit("lose");
                stop();
            } else {
                var t = generateType();
                var d = generateDir();
                game.performNext(t, d);
                socket.emit("next", {
                    type: t,
                    dir: d,
                });
            }
        } else {
            socket.emit("down");
        }
    };
    // 计时函数
    var timeFunc = function () {
        timeConut = timeConut + 1;
        if (timeConut == 5) {
            timeConut = 0;
            time = time + 1;
            // 将更新的时间传入界面
            game.setTime(time);
            socket.emit("time", time);
        }
    };
    // 随机生成下一个方块
    var generateType = function () {
        // 随机生成0-6的整数
        return Math.ceil(Math.random() * 7) - 1;
    };
    // 随机生成旋转次数
    var generateDir = function () {
        // 随机生成0-3的整数
        return Math.ceil(Math.random() * 4) - 1;
    };

    // 开始
    var start = function () {
        var doms = {
            gameDiv: document.getElementById("local_game"),
            nextDiv: document.getElementById("local_next"),
            timeDiv: document.getElementById("local_time"),
            scoreDiv: document.getElementById("local_score"),
            resultDiv: document.getElementById("local_gameover"),
        };
        game = new Game();

        // 定义变量,用websocket将随机方向种类和方向generateType(), generateDir()通过对象形式到init,
        var type = generateType();
        var dir = generateDir();
        game.init(doms, type, dir);
        socket.emit("init", {
            type: type,
            dir: dir,
        });
        bindKeyEvent();
        var t = generateType();
        var d = generateDir();
        game.performNext(t, d);
        socket.emit("next", {
            type: t,
            dir: d,
        });
        timer = setInterval(move, INTERVAL);
    };
    // 结束,关闭计时
    var stop = function () {
        if (timer) {
            clearInterval(timer);
            timer = null;
        }
        document.onkeydown = null;
    };
    // 不用导出start了,用socket.on监听start,收到后,通过waiting设置页面显示为空;调用start开始游戏
    socket.on("start", function () {
        document.getElementById("waiting").innerHTML = "游戏开始!";
        start();
    });
    socket.on("lose", function () {
        game.gameOver(true);
        stop();
    });
    socket.on("leave", function () {
        document.getElementById("local_gameover").innerHTML = "对方掉线啦";
        document.getElementById("remote_gameover").innerHTML = "已掉线";
        stop();
    });
    socket.on('bottomLines', function (data) {
        game.addTailLines(data);
        socket.emit('addTailLines', data);
    })
};

remote.js

var Remote = function (socket) {
    var game;
    var bindEvents = function () {
        socket.on('init', function (data) {
            // 调用start,接收init消息和传递的参数,实现两个用户相连接(在对方区域中调用了start)
            start(data.type, data.dir);
        });
        socket.on('next', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.performNext(data.type, data.dir);
        });
        socket.on('rotate', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.rotate();
        });
        socket.on('right', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.right();
        });
        socket.on('left', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.left();
        });
        socket.on('down', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.down();
        });
        socket.on('line', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.checkClear();
            game.addScore(data);
        });
        socket.on('fall', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.fall();
        });
        socket.on('fixed', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.fixed();

        });
        socket.on('time', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.setTime(data);

        });
        socket.on('lose', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.gameOver(false);
        });
        socket.on('addTailLines', function (data) {
            // 驱动对方游戏区域也调用performNext函数
            game.addTailLines(data);
        });
    }
    var start = function (type, dir) {
        var doms = {
            gameDiv: document.getElementById('remote_game'),
            nextDiv: document.getElementById('remote_next'),
            timeDiv: document.getElementById('remote_time'),
            scoreDiv: document.getElementById('remote_score'),
            resultDiv: document.getElementById('remote_gameover')
        }
        game = new Game();
        game.init(doms, type, dir);
    }
    bindEvents();
}

wsServer.js

var app = require("http").createServer();
var io = require("socket.io")(app);

var PORT = 3000;
// 客户端计数
var clientCount = 0;
// 保存客户端socket
var socketMap = {};
app.listen(PORT);

var bindListener = function (socket, event) {
    socket.on(event, function (data) {
        if (socket.clientNum % 2 == 0) {
            if (socketMap[socket.clientNum - 1])
                socketMap[socket.clientNum - 1].emit(event, data);
        } else {
            if (socketMap[socket.clientNum + 1])
                socketMap[socket.clientNum + 1].emit(event, data);
        }
    });
}
io.on("connection", function (socket) {
    // 用户连接进来后先进行客户加1
    clientCount++;
    socket.clientNum = clientCount;
    socketMap[clientCount] = socket;
    // 是单数个进来的用户需要等待
    if (clientCount % 2 == 1) {
        // 发送wait消息
        socket.emit("waiting", "等待玩家进入……");
    } else {
        if (socketMap[clientCount - 1]) {
            socket.emit("start");
            socketMap[(clientCount - 1)].emit("start");
        } else {
            socket.emit('leave');
        }
    }
    bindListener(socket, 'init');
    bindListener(socket, 'next');
    bindListener(socket, 'rotate');
    bindListener(socket, 'down');
    bindListener(socket, 'right');
    bindListener(socket, 'left');
    bindListener(socket, 'fall');
    bindListener(socket, 'fixed');
    bindListener(socket, 'line');
    bindListener(socket, 'time');
    bindListener(socket, 'lose');
    bindListener(socket, 'bottomLines');
    bindListener(socket, 'addTailLines');

    socket.on('disconnect', function () {
        if (socket.clientNum % 2 == 0) {
            if (socketMap[socket.clientNum - 1])
                socketMap[socket.clientNum - 1].emit('leave');
        } else {
            if (socketMap[socket.clientNum + 1])
                socketMap[socket.clientNum + 1].emit('leave');
        }
        delete(socketMap[socket.clientNum]);
    });
});


console.log("websocket listening on port" + PORT);

script.js

var socket = io('ws://localhost:3000');
// 创建local对象并调用,传入socket对象
var local = new Local(socket);
var remote = new Remote(socket);

socket.on('waiting', function (str) {
    document.getElementById('waiting').innerHTML = str;
});

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以前先后上传过俄罗斯方块1.0和2.0,1.0只支持单机,2.0在1.0的基础上加了自己的socket类,实现了局域网联机对战功能,现在上传的是3.0,又加了个录像功能。(右键打开快捷菜单) 先把2.0的功能再复制过来一下: 1.服务器端与客户端对战,没有同时开始功能,速度也可以不一样,下落方块的种类也不是按同样的次序,没有道具功能,只是将自己的战况实时传输给对方; 2.由于我的socket类支持多个客户端连接,但是联机时只有两个视窗,一个自己的,一个对家的,所以当多个客户端接入服务器端时具体表现为:服务器端的战况都会广播给所有客户端,相当于大家观看服务器端演示,但是服务器端不显示任何一个客户端的战况;而当只有一个客户端连接服务器端时,才显示这个客户端的战况。 3.加入游戏,断开连接这两个功能在执行时,是另开线程的,我故意让关闭按钮和拖曳客户端区域移动窗口功能失效,看上去像是程序当住了,其实没当住,因为此时拖曳标题栏还是能移动窗口,右键菜单也可以弹出,这个“当住”过程会在3秒钟左右,当客户端比较多时,服务器端的这个时间会相对长一点。 现在简要说一下3.0的录像文件格式: 录像文件是以32位的BITMAPINFOHEADER类型位图文件的形式保存的, 因为考虑到位图须4字节对齐,而32位的位图具有对齐方面的天然优势,处理方便, 真正的数据区从位图文件的图素区开始,忽略位图的文件头和信息头; 程序里附带有4个录像文件是我打的。 有问题联系:hastings1986@163.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值