javascript - 将多个套接字实例绘制到 Canvas 上并在移动时更新(多人游戏)

标签 javascript node.js canvas socket.io

计划

我决定开始尝试使用 Node.js 和 Socket.io 并着手制作一款游戏(或者只是一个将每个玩家绘制并显示为一个 block 的大厅)。每次客户端加入时,服务器都应该使用该类并实例化一个新对象,其中包含服务器提供的玩家详细信息(随机)。

服务器随后将使用 socket.io 并将新对象发送给连接的客户端,这样他们就可以拥有该对象,然后可以使用它做一些事情(在本例中为移动)。

客户端应该做的第一件事是将所有用户绘制到 Canvas 上,然后将当前客户端也绘制到 Canvas 上。


问题

我已经到了工作正常的地步,服务器创建了一个新的播放器对象,然后将其发送给客户端,然后客户端将能够使用属性将自己绘制到 Canvas 上,但我似乎无法拥有客户端被发送到其他用户的 Canvas 上绘制,直到我移动播放器。

当我打开多个浏览器选项卡时,它会按预期方式绘制客户端,如下所示:

enter image description here

但是当我移动其中一个时,一个客户确实成功地吸引了其他客户,但其他客户都失去了那一刻给他们的对象,直到他们移动然后它成功地移动到其他地方,然后是另一个客户都失去了屏幕状态,您可以在其中看到他们的位置。简而言之,他们都在屏幕上,并相应地移动到所有浏览器中的正确位置,但是当它发生时你永远看不到所有玩家它一次只显示一个玩家,那就是那个移动的人(在你第一次加入你的地方之后也只能看到自己,直到有人移动,然后你才能看到所有玩家,只有最后移动,直到有人或你移动)。 查看下面的图片

enter image description here

上面显示我聚焦中间选项卡并移动,日志显示发生了什么(注意其他玩家都消失了,只显示移动的玩家)


代码

我只有 2 个正在使用的文件,它们的填充如下。

服务器 - nodejs

var express = require('express'),
    app = express(),
    http = require('http').createServer(app),
    io = require('socket.io').listen(http);

http.listen(8000);

//server connections and routing
app.use(express.static(__dirname + '/public'), function(request, response){
    if(request.url !== '/public') {
        response.sendFile( __dirname +'/error/index.html');
        console.log('Error 404 request, User tried accessing: ' + __dirname + request.url);
    }
});

var players = [];

//Lets create a function which will help us to create multiple players
function newPlayer() {
    this.name;
    this.id = 1;
    this.x = Math.random() * 500;
    this.y =  Math.random() * 500;
    //Random colors
    var r = Math.random()*255>>0;
    var g = Math.random()*255>>0;
    var b = Math.random()*255>>0;
    this.color = "rgba(" + r + ", " + g + ", " + b + ", 0.5)";

    //Random size
    this.radius = Math.random()*20+20;
    this.speed =  5;

    return {'name' : this.name,"x" : this.x,"y" : this.y,"color" : this.color, "radius" : this.radius,"speed" : this.speed}
}

//calls to the server and tracking connection of each new user
io.sockets.on('connection', function(socket){
    var currentPlayer = new newPlayer(); //new player made
    players.push(currentPlayer); //push player object into array

    //create the player
    socket.broadcast.emit('createUsers', players);
    socket.emit('currentUser', currentPlayer);

    //user moved
    socket.on('moved', function(data){
        console.log(data);
        socket.broadcast.emit('moving', data);
    });

    //disconnected
    socket.on('disconnect', function(){
        var i = players.indexOf(currentPlayer);
        players.splice(i, 1);
        socket.broadcast.emit('user left','User: ' + currentPlayer.name + ' Left');
        console.log(players);
    });

});

console.log('NodeJS Server started on port 8000...');

客户端 - HTML

<!doctype html>
<html>
<head>
    <title>Game Dev JS - 1</title>
    <link href="./ui.css" rel="stylesheet">
</head>
<body>
    <canvas id="canvas" width="500" height="500">
        Your Browser Does Not Support Canvas and HTML5
    </canvas>
</body>
    <script type="text/javascript" src="/socket.io/socket.io.js"></script>
    <script type="text/javascript" src="/js/engine.js"></script>

</html>

客户端 - CSS

body{
    margin: 0 auto;
    width: auto;
    background: #fff;
    text-align: center;
}

#canvas {
    margin: 15px;
    background: #000;
}

客户端 - Javascript

var socket = io.connect(); //add socket object

//initializing the canvas
var canvas = document.getElementById("canvas"),
    ctx = canvas.getContext('2d'),
    W = window.innerWidth,
    H = window.innerHeight;

var keys = {};

window.addEventListener('keydown', function(e){
    keys[e.keyCode] = true; 
}, false);

//check if ke is not being pressed or has lifted up
window.addEventListener('keyup', function(e){
    delete keys[e.keyCode];
}, false);

socket.on('currentUser', function(newUser){
    ctx.fillStyle = newUser.color;
    ctx.fillRect(newUser.x, newUser.y, 25, 25);

    function update(){
        //moving player
        if(keys[38]){
            newUser.y -= newUser.speed;
            socket.emit('moved', newUser);
            console.clear();
            console.log('You Moving');
            console.log(newUser);
            ctx.clearRect(0, 0, W, H);
            ctx.fillStyle = newUser.color;
            ctx.fillRect(newUser.x, newUser.y, 25, 25);
        } 
        if(keys[40]){
            newUser.y += newUser.speed;
            socket.emit('moved', newUser);
            console.clear();
            console.log('You Moving');
            console.log(newUser);
            ctx.clearRect(0, 0, W, H);
            ctx.fillStyle = newUser.color;
            ctx.fillRect(newUser.x, newUser.y, 25, 25);
        } 
        if(keys[37]){
            newUser.x -= newUser.speed;
            socket.emit('moved', newUser);
            console.clear();
            console.log('You Moving');
            console.log(newUser);
            ctx.clearRect(0, 0, W, H);
            ctx.fillStyle = newUser.color;
            ctx.fillRect(newUser.x, newUser.y, 25, 25);
        } 
        if(keys[39]){
            newUser.x += newUser.speed;
            socket.emit('moved', newUser);
            console.clear();
            console.log('You Moving');
            console.log(newUser);
            ctx.clearRect(0, 0, W, H);
            ctx.fillStyle = newUser.color;
            ctx.fillRect(newUser.x, newUser.y, 25, 25);
        }
        window.requestAnimationFrame(update);
    }
    update();
});

//moving player and updating on other clients
socket.on('moving', function(moveTo){
    ctx.clearRect(0, 0, W, H);
    ctx.fillStyle = moveTo.color;
    ctx.fillRect(moveTo.x, moveTo.y, 25, 25);
    console.clear();
    console.log('A Player Moved');
    console.log(moveTo);
});

注意事项

我会把它放在一个 fiddle 的某个地方供你玩,但我不知道有什么可以让我用 node.js 服务器进行测试并让你同时查看代码,比如JS fiddle 。我还是 Node 和 Socket.io 的新手,这是我的第一次尝试,任何帮助对我来说都是奖励。一旦主要功能有序,我将着手重构代码。

如果您安装了 npm 并安装了 socket.io,那么您应该能够复制和粘贴它并且它应该可以工作。我的文件夹结构如下 - 这没有任何问题,因为一切都正确加载

enter image description here

提前致谢

最佳答案

moving 事件的客户端监听器将永远只允许客户端一次绘制一个玩家的位置。您正在清除整个屏幕,删除所有其他位置,但随后只重新绘制移动的玩家。

我会推荐阅读 Robert Nystrom 的优秀游戏编程模式电子书 http://gameprogrammingpatterns.com/contents.html .它不涵盖这种特定情况,但您可以从 Observer、Game Loop 和 Update 部分推断出很多内容。在您的情况下,您可能希望服务器运行权威游戏循环和状态,使用观察者更新客户端/服务器之间的状态,并且客户端使用自己的独立游戏循环向用户显示所述状态。

关于javascript - 将多个套接字实例绘制到 Canvas 上并在移动时更新(多人游戏),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34187326/

相关文章:

javascript - 失去焦点时关闭即时验证

canvas - 有没有办法在 tkinter 中从 TreeView 拖放到 Canvas 上?

canvas - 如何让 canvas% 对象响应鼠标悬停?

javascript - HTML Canvas 和 JavaScript - 悬停时缩放对象

javascript - D3.js Bilevel Partition - 初始图表加载切片放大

javascript - 如何运行 Php 脚本使用 cronjob 静默包含 javascript

node.js - 如何从 node.js 中的 mysql SELECT 查询返回值

javascript - 使用 minikube 部署多页面 Web 应用程序

javascript - Mongoose 不使用模型 save() 强制执行类型

javascript - VML非零绕组