原始地址:https://dev.to/sauravmh/building-a-multiplayer-game-using-websockets-1n63
‘’’
构建多人游戏的终极指南,使用NodeJS和React上的socket.io以正确的方式在浏览器上。 从文件夹结构到项目部署
在创意独特的项目中入门非常重要。但是在开始项目时,正确方向的重要性更为关键。
“未来属于那些学习的更多技能并以创造性的方式将它们结合起来的人。”
- 罗伯特·格林,《掌握技巧》
为什么需要另一个教程?
这点非常重要要澄清。 线上有很多关于“开始使用socket.io”的重点在于“开始使用socket.io的指南”,当它们都是聊天应用程序时,这会让人更加沮丧。但是在这里,我们将重点放在“开始使用Socket.io构建可扩展项目”,它不是一个聊天应用程序:)
这个指南将更多地解释代码基础设施,而不是专注于UI /UX。 因此,如果UI看起来不太吸引人,请容忍一下。
什么是socket.io?
Socket.io是建立在WebSocket协议之上的抽象。WebSocket是一种协议,允许客户端和服务器之间进行双向同步交换。或者用简单的话说,它是一个双向通信管道。
注意:在本文中,WebSocket和socket.io将交替使用(尽管它们在某些方面是不同的),除非另有说明。
为什么选择WebSockets而不是HTTP?
对于实时多人游戏,我们需要客户端向服务器发送信息数据包,并且服务器需要同时发送/广播数据。这不能使用HTTP实现,因为客户端必须向服务器发送请求才能接收到某些内容。这对于多人游戏来说并不可行。
你所说的“正确方式”是什么意思?
所谓“正确方式”指的是开始一个可以轻松扩展的代码库,并且对于较小的项目不会造成太多麻烦。它涉及到可以遵循的常见做法,从而使项目更具模块化。这绝不意味着这是构建WebSockets项目的官方方式。但这只是我的个人意见,你可以轻松替换掉你不喜欢的项目的部分组件:D
这个项目是关于什么的? ⚡⚡
接下来介绍这个指南的核心。这个指南通过一个真实的项目解释了如何构建一个“多人socket.io游戏”。通过实践项目,我们能更容易地看到项目的运行过程,也知道代码/基础结构是有效的!这个项目是…
多人足球选秀模拟器
这个游戏是做什么的? ⚡
这是一个回合制多人游戏。人们进入并创建一个房间。其他人加入房间。然后游戏开始,所有玩家都被洗牌,第一个人有机会选择他想要的足球运动员。他可以从球员列表中搜索(查看他们的统计数据、位置、评级和其他详细信息),并在分配时间内确认他的选择。现在,轮到另一个玩家了。一直重复,直到每个人都选完了自己的整个足球队。
相当简单吧?是/不是,不要紧。我们将详细介绍这背后的代码基础结构。
游戏架构
上图解释了从鸟瞰的角度如何连接一切。
本指南中的HTTP和Websockets服务器都使用NodeJS。我们使用Redis数据库,因为socket.io支持其开箱即用的集成,而且读写操作速度更快,因为数据存储在内存中。MongoDB用作更持久的存储解决方案。游戏结果和每个房间的用户团队在每轮选秀结束后都存储在MongoDB中。如果希望注册,它还会存储用户凭据(该项目有一个可选的注册/登录步骤)。
WebCrawler是使用Python3编写的,使用Scrapy库。足球球员数据集是从https://sofifa.com抓取的。它包括超过20,000名球员的评级、统计数据、价值、俱乐部等信息。它还有一个可选的数据分析jupyter-notebook,用于处理抓取的数据,但本指南不讨论这方面的内容。
文件夹结构(ExpressJS + MongoDB + socket.io)
NodeJS不会强制规定代码结构。这给了我们很大的灵活性来设计它们,但是你可能会遇到严重的问题,导致项目难以维护和扩展。在与sockets + NodeJS一起工作时,可以使用此特定项目结构
让我们深入了解项目代码库的结构
.{src}
├── controller
│ ├── authController.js#处理身份验证请求
│ ├── searchController.js#处理搜索查询
│ ├── userController.js#处理用户档案操作
│ └── …
│
├── database
│ ├── db.js#初始化数据库连接
│ └── …
│
├── middlewares
│ ├── authenticated.js#解码和验证JWT令牌
│ ├── error.js#通用错误处理程序
│ ├── logger.js#控制日志级别
│ └── …
│
├── models
│ ├── roomsModels.js#房间的数据库模型
│ ├── usersModel.js#用户的数据库模型
│ └── …
│
├── schema
│ ├── rooms.js#房间的数据库架构
│ ├── users.js#用户的数据库架构
│ └── …
│
├── socker
│ ├── roomManager.js#Socket监听器/发射器处理
│ ├── sockerController.js#控制Socket连接
│ └── …
│
├── app.js#项目入口文件
├── env.js#存储环境变量
├── routes.js#所有路由初始化
└── …
后端根据项目要求分为不同的目录。如果您想跳过或交换某些模块,只需添加另一个目录即可。
大多数子目录对于Node项目是常见的,所以我不会在这里详细解释它们。每个目录旁边的注释应该可以了解它的大致内容。
我们将更多关注子目录 socker/。这是你的核心socket.io代码所在的地方。
socket.io的入口点(App.js)
这里创建了两个服务器,
app - 监听HTTP请求和
server - 监听WebSockets连接。建议将它们连接到不同的端口以避免混淆。
你可能想知道第1行和第8行的“socker”是什么。
什么是socker?
Socker只是一个函数别名(因为我正在这里创建一个足球选秀游戏,呵呵!)。这个函数将
Server(在app.js的第8行传递)附加到新的
http.Server的engine.io实例上。简单地说,它将socket.io引擎附加到传递给它的服务器上。
但是上面的代码并没有解释太多。现在,以下问题出现了:
- 如何与连接的客户端进行交互?
- 命名空间在哪里?
- 房间/频道在哪里?
- 最重要的是,游戏在哪里?
创建命名空间以及为什么创建命名空间?
命名空间是socket.io的一个重要功能。它代表一个socket池,位于特定范围的的sockets下,由类似/classic-mode、/football-draft、/pokemon-draft等的路径名识别。这基本上是创建不同的端点或路径。它允许我们最小化资源(TCP连接)数量,并且同时在应用程序中通过引入通信通道之间的分离来分离关注点。默认情况下,socket.io连接到/命名空间。
创建房间/频道以及为什么创建房间/频道?
在每个命名空间内,您可以创建任意的通道或房间。这进一步允许您创建可以
加入或
离开的连接。在这里,我们使用
channels 创建不同的房间,用户可以加入或创建以一起玩。
加入房间的示例
join()操作检查所需的
roomId 是否已经创建。如果尚未创建,则创建该房间并将玩家添加到给定的roomId。如果已经创建,它直接加入房间。
一个概括使用命名空间和通道的示例:
第I部分到此结束。此处显示的代码结构对于中等大小的项目非常有效。如果您正在构建一个快速原型,可以省略或合并模式和模型文件夹。如果需要,可以随时轻化项目,不要犹豫:)
如果项目规模增大会怎样?当前的结构可能不适用。可以根据需要创建子文件夹来满足服务和组件的要求(用户认证,tests,分析等)。甚至可以创建微服务,即分别部署每个过程或服务,从而可以在重负载下仅负载平衡或扩展进程。
记住,不要过度设计产品,分阶段构建和部署!
无论是笑话还是工程项目,没有人喜欢做得过度:)
如果你感兴趣,这是我的项目链接:
- 后端(Websockets + HTTP)-
https://github.com/sauravhiremath/fifa-api - 前端(ReactJS)-
https://github.com/sauravhiremath/fifa - 网络爬虫(Python3 + Scrapy)-
https://github.com/sauravhiremath/fifa-stats-crawler **下一篇文章/文章的重点: ** - 为每个命名空间创建和处理房间。
- 对项目客户端的简要说明(ReactJS)
- 每个项目包的CI和部署。
如果您有任何问题或对未来的文章有任何建议,请告诉我。
✌️
️祝您度过愉快的一天!
关注我的twitter @
[sauravmh]获取最新动态!
‘’’