4

在页游时代,大部分游戏都是通过socket来实现玩家之间的实时通信互动的,在H5时代,利用websocket,我们也同样可以达到这个目的,并且目前websocket的浏览器兼容度已经很高,下面记录一下基于socket.io库来实现H5画板功能的过程,非常的简单方便。

socket.io

socket.io是一个基于Node.js的websocket库,可以方便快捷地在web端建立socket通信。

安装

npm install socket.io    

启动服务器

安装好socket.io后,我们建立app.js(服务器的入口程序),添加如下代码:

var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');

// socket端口
app.listen(8080);

// 处理请求
function handler(req, res) {
    res.writeHead(200);
    res.end('Hello World2\n');
}

// 客户端连接的事件处理函数
io.on('connection', function(socket) {
    // todo...
});

上面简单的几行代码已经建立了一个socket服务器,并且能处理客户端的连接与收发消息。

建立客户端连接

// 连接socket
var socket = io('http://localhost');
// 监听画图消息
socket.on('draw-event', function(data) {
    console.log(data);
    // 处理画图消息
    if (data.type == 'start') {
        onTouchStart(data.x, data.y);
    } else if (data.type == 'move') {
        onTouchMove(data.x, data.y);
    }
});

房间

在同一个房间里的所有用户可以很方便的管理和传递消息,默认情况下,socket.io都是为每个用户创建一间房间,并且房间id存在socket.id属性中。我们在第一个用户进入时取到房间号,然后通过二维码方式让后面的用户扫码,后面的用户通过扫码进入时加入到指定的房间。

前端逻辑:

socket.on('connect', function() {
    // 判断是通过扫码进入房间还是房主
    if (isHost) {
        // 生成二维码
        new QRCode(document.getElementById("qrcode"), url + '?r=' + socket.id);
        console.log('url', url + '?r=' + socket.id)
    } else {
        // 发消息给服务器加入房间
        socket.emit('sys', {
            type: 'join',
            roomId: params.r
        });
    }
});

上面的代码用到了QRCode.js这个前端库生成代码。

后端逻辑:

// 处理系统消息
socket.on('sys', function(data) {
    console.log(data);
    if (data.type == 'join') {
        // 猜的一方进入房间
        console.log(socket.id + ' join room: ' + data.roomId);
        socket.join(data.roomId);
        // 通知房间其它用户
        io.in(data.roomId).emit('sys', { type: 'join', roomId: data.roomId });
    }
});

画图消息

画图是用canvas的绘图实现的,核心部分代码:

// 笔触移动
$('#canvas').on('touchmove', function(event) {
    touch = event.touches[0];
    render();
    // 发送到后端
    socket.emit('draw-event', {
        type: 'move',
        x: touch.pageX,
        y: touch.pageY,
    });
}).on('touchstart', function(event) { // 点击屏幕
    event.preventDefault();
    touch = event.touches[0];
    onTouchStart(touch.pageX, touch.pageY);
    isTouched = true;
    // 发送到后端
    socket.emit('draw-event', {
        type: 'start',
        x: touch.pageX,
        y: touch.pageY,
    });
}).on('touchend', function(event) { // 离开屏幕
    event.preventDefault();
    isTouched = false;
    touch = null;
});

...

var render = function() {
    onTouchMove(touch.pageX, touch.pageY);
};

var onTouchStart = function(x, y) {
    context.moveTo(x - canvasOffset.left, y - canvasOffset.top);
};

var onTouchMove = function(x, y) {
    context.lineTo(x, y);
    context.stroke();
    context.moveTo(x - canvasOffset.left, y - canvasOffset.top);
    console.log(x, y)

};

后端转发消息给另外的客户端:

socket.on('draw-event', function(data) {
    console.log(data);
    // 转发画图消息
    socket.to(roomId).emit('draw-event', data);
});

接收方处理消息:

socket.on('draw-event', function(data) {
    console.log(data);
    if (data.type == 'start') {
        onTouchStart(data.x, data.y);
    } else if (data.type == 'move') {
        onTouchMove(data.x, data.y);
    }
});

结语

至此,一个简单的通过websocket进行实时通信交互的例子实现了,我们通过扩展细节,可以做成我画你猜的画图游戏,也可以发挥创造力做出更多好玩的交互。


cybs
216 声望3 粉丝