通过示例在 Unity 和 NodeJS 上的游戏中创建安全、快速的多人游戏
在IT行业这个发展更新速度很快的行业,只有不停止的学习,才不会被行业所淘汰。如果你是文章学习者,那么本文《通过示例在 Unity 和 NodeJS 上的游戏中创建安全、快速的多人游戏》就很适合你!本篇内容主要包括##content_title##,希望对大家的知识积累有所帮助,助力实战开发!
介绍
规划多人游戏开发方法 - 在整个项目的进一步开发中发挥着最重要的作用之一,因为它包含了我们在创建真正高质量的产品时应该考虑的许多标准。在今天的宣言教程中,我们将看一个方法示例,该方法使我们能够创建真正快速的游戏,同时尊重所有安全和反违规规则。

所以,让我们定义我们的主要标准:
- 多人游戏需要一种特殊的方法来管理网络同步,尤其是在实时情况下。 二进制协议用于加速客户端之间的数据同步,反应字段将有助于以最小的延迟和节省内存来更新玩家位置。
- 服务器权限是一项重要原则,关键数据仅在服务器上处理,确保游戏完整性并防止作弊。然而,为了让我们最大限度地提高性能 - 服务器只进行关键更新,剩下的交给客户端反作弊。
- 实施客户端反投诉,以便在服务器上不增加负载的情况下处理不太关键的数据。

架构的主要组成部分
- 客户端(unity):客户端负责显示游戏状态,将玩家操作发送到服务器并从服务器接收更新。这里还使用反应字段来动态更新玩家位置。
- 服务器端(node.js):服务器处理关键数据(例如,移动、碰撞和玩家动作)并将更新发送到所有连接的客户端。非关键数据可以在客户端上处理并使用服务器转发到其他客户端。
- 二进制协议:二进制数据序列化用于减少传输的数据量并提高性能。
- 同步:提供客户端之间数据的快速同步,以最大程度地减少延迟并确保流畅的游戏体验。
- 客户端反作弊:它用于我们可以在客户端上更改并发送给其他客户端的数据。
第 1 步:在 node.js 中实现服务器
首先,您需要在 node.js 上设置一个服务器。服务器将负责所有关键计算并将更新的数据传输给玩家。
安装环境
要在 node.js 上创建服务器,请安装必要的依赖项:
mkdir multiplayer-game-server cd multiplayer-game-server npm init -y npm install socket.io
socket.io可以轻松地使用web套接字实现客户端和服务器之间的实时双向通信。
基本服务器实现
让我们创建一个简单的服务器,它将处理客户端连接、检索数据、计算关键状态并在所有客户端之间同步它们。
// create a simple socket io server
const io = require('socket.io')(3000, {
cors: {
origin: '*'
}
});
// simple example of game states
let gamestate = {};
let playerspeedconfig = {
maxx: 1,
maxy: 1,
maxz: 1
};
// work with new connection
io.on('connection', (socket) => {
console.log('player connected:', socket.id);
// initialize player state for socket id
gamestate[socket.id] = { x: 0, y: 0, z: 0 };
// work with simple player command for movement
socket.on('playermove', (data) => {
const { id, dx, dy, dz } = parseplayermove(data);
// check maximal values
if(dx > playerspeedconfig.maxx) dx = playerspeedconfig.maxx;
if(dy > playerspeedconfig.maxy) dx = playerspeedconfig.maxy;
if(dz > playerspeedconfig.maxz) dx = playerspeedconfig.maxz;
// update game state for current player
gamestate[id].x += dx;
gamestate[id].y += dy;
gamestate[id].z += dz;
// send new state for all clients
const updateddata = serializegamestate(gamestate);
io.emit('gamestateupdate', updateddata);
});
// work with unsafe data
socket.on('dataupdate', (data) => {
const { id, unsafe } = parseplayerunsafe(data);
// update game state for current player
gamestate[id].unsafevalue += unsafe;
// send new state for all clients
const updateddata = serializegamestate(gamestate);
io.emit('gamestateupdate', updateddata);
});
// work with player disconnection
socket.on('disconnect', () => {
console.log('player disconnected:', socket.id);
delete gamestate[socket.id];
});
});
// simple parse our binary data
function parseplayermove(buffer) {
const id = buffer.tostring('utf8', 0, 16); // player id (16 bit)
const dx = buffer.readfloatle(16); // delta x
const dy = buffer.readfloatle(20); // delta y
const dz = buffer.readfloatle(24); // delta z
return { id, dx, dy, dz };
}
// simple parse of unsafe data
function parseplayerunsafe(buffer) {
const id = buffer.tostring('utf8', 0, 16); // player id (16 bit)
const unsafe = buffer.readfloatle(16); // unsafe float
return { id, unsafe };
}
// simple game state serialization for binary protocol
function serializegamestate(gamestate) {
const buffers = [];
for (const [id, data] of object.entries(gamestate)) {
// player id
const idbuffer = buffer.from(id, 'utf8');
// position (critical) buffer
const posbuffer = buffer.alloc(12);
posbuffer.writefloatle(data.x, 0);
posbuffer.writefloatle(data.y, 4);
posbuffer.writefloatle(data.z, 8);
// unsafe data buffer
const unsafebuffer = buffer.alloc(4);
unsafebuffer.writefloatle(data.unsafevalue, 0);
// join all buffers
buffers.push(buffer.concat([idbuffer, posbuffer, unsafebuffer]));
}
return buffer.concat(buffers);
}
此服务器执行以下操作:
- 处理客户端连接。
- 接收二进制格式的玩家移动数据,验证它,更新服务器上的状态并将其发送到所有客户端。
- 以最小延迟同步游戏状态,使用二进制格式来减少数据量。
- 简单地转发来自客户端的不安全数据。
要点:
- 服务器权限:所有重要数据均在服务器上处理和存储。客户端仅发送操作命令(例如,位置变化增量)。
- 二进制数据传输:使用二进制协议可以节省流量并提高网络性能,特别是对于频繁的实时数据交换。
第2步:在unity上实现客户端部分
现在让我们在 unity 上创建一个与服务器交互的客户端部分。
要将 unity 连接到 socket.io 上的服务器,您需要连接专为 unity 设计的库。
在这种情况下,我们不受任何特定实现的约束(事实上它们都是相似的),而只是使用一个抽象示例。
使用反应字段进行同步
我们将使用反应字段来更新玩家位置。这将使我们能够更新状态,而无需通过 update() 方法检查每个帧中的数据。当数据状态发生变化时,反应字段会自动更新游戏中对象的视觉表示。
要获得反应性属性功能,您可以使用 unirx。
unity 上的客户端代码
让我们创建一个脚本来连接到服务器、发送数据并通过反应字段接收更新。
using UnityEngine;
using SocketIOClient;
using UniRx;
using System;
using System.Text;
// Basic Game Client Implementation
public class GameClient : MonoBehaviour
{
// SocketIO Based Client
private SocketIO client;
// Our Player Reactive Position
public ReactiveProperty<Vector3> playerPosition = new ReactiveProperty<Vector3>(Vector3.zero);
// Client Initialization
private void Start()
{
// Connect to our server
client = new SocketIO("http://localhost:3000");
// Add Client Events
client.OnConnected += OnConnected; // On Connected
client.On("gameStateUpdate", OnGameStateUpdate); // On Game State Changed
// Connect to Socket Async
client.ConnectAsync();
// Subscribe to our player position changed
playerPosition.Subscribe(newPosition => {
// Here you can interpolate your position instead
// to get smooth movement at large ping
transform.position = newPosition;
});
// Add Movement Commands
Observable.EveryUpdate().Where(_ => Input.GetKey(KeyCode.W)).Subscribe(_ => ProcessInput(true));
Observable.EveryUpdate().Where(_ => Input.GetKey(KeyCode.S)).Subscribe(_ => ProcessInput(false));
}
// On Player Connected
private async void OnConnected(object sender, EventArgs e)
{
Debug.Log("Connected to server!");
}
// On Game State Update
private void OnGameStateUpdate(SocketIOResponse response)
{
// Get our binary data
byte[] data = response.GetValue<byte[]>();
// Work with binary data
int offset = 0;
while (offset < data.Length)
{
// Get Player ID
string playerId = Encoding.UTF8.GetString(data, offset, 16);
offset += 16;
// Get Player Position
float x = BitConverter.ToSingle(data, offset);
float y = BitConverter.ToSingle(data, offset + 4);
float z = BitConverter.ToSingle(data, offset + 8);
offset += 12;
// Get Player unsafe variable
float unsafeVariable = BitConverter.ToSingle(data, offset);
// Check if it's our player position
if (playerId == client.Id)
playerPosition.Value = new Vector3(x, y, z);
else
UpdateOtherPlayerPosition(playerId, new Vector3(x, y, z), unsafeVariable);
}
}
// Process player input
private void ProcessInput(bool isForward){
if (isForward)
SendMoveData(new Vector3(0, 0, 1)); // Move Forward
else
SendMoveData(new Vector3(0, 0, -1)); // Move Backward
}
// Send Movement Data
private async void SendMoveData(Vector3 delta)
{
byte[] data = new byte[28];
Encoding.UTF8.GetBytes(client.Id).CopyTo(data, 0);
BitConverter.GetBytes(delta.x).CopyTo(data, 16);
BitConverter.GetBytes(delta.y).CopyTo(data, 20);
BitConverter.GetBytes(delta.z).CopyTo(data, 24);
await client.EmitAsync("playerMove", data);
}
// Send any unsafe data
private async void SendUnsafeData(float unsafeData){
byte[] data = new byte[20];
Encoding.UTF8.GetBytes(client.Id).CopyTo(data, 0);
BitConverter.GetBytes(unsafeData).CopyTo(data, 16);
await client.EmitAsync("dataUpdate", data);
}
// Update Other players position
private void UpdateOtherPlayerPosition(string playerId, Vector3 newPosition, float unsafeVariable)
{
// Here we can update other player positions and variables
}
// On Client Object Destroyed
private void OnDestroy()
{
client.DisconnectAsync();
}
}
第 3 步:优化同步和性能
为了确保流畅的游戏体验并最大程度地减少同步期间的延迟,建议:
- 使用插值:客户端可以使用插值来平滑服务器更新之间的移动。这可以补偿较小的网络延迟。
- 批量数据发送:不要按每一步发送数据,而是使用批量发送。例如,每隔几毫秒发送一次更新,这将减少网络负载。
- 降低更新频率:将发送数据的频率降低到合理的最低限度。例如,对于大多数游戏来说,每秒更新 20-30 次可能就足够了。
如何简化二进制协议的使用?
为了简化您使用二进制协议的工作 - 创建数据处理的基本原理以及与其交互的方案。
对于我们的示例,我们可以采用一个基本协议,其中:
1) 前 4 位是用户发出的请求的最大值(例如 0 - 移动玩家,1 - 射击等);
2) 接下来的 16 位是我们客户的 id。
3) 接下来我们填充通过循环传递的数据(一些网络变量),其中存储变量的 id、到下一个变量开头的偏移量(以字节为单位)、变量的类型和它的价值。
为了方便版本和数据控制 - 我们可以以方便的格式(json / xml)创建客户端-服务器通信模式,并从服务器下载一次,以便根据该模式进一步解析我们的二进制数据以获得所需的内容我们的 api 版本。
客户端反作弊
在服务器上处理所有数据是没有意义的,其中一些数据更容易在客户端修改并发送到其他客户端。
为了让你在这个方案中更加安全 - 你可以使用客户端防黑客系统来防止内存黑客 - 例如,我的 gameshield - 一个免费的开源解决方案。
结论
我们举了一个简单的例子,在 unity 上使用 node.js 服务器开发多人游戏,所有关键数据都在服务器上处理,以确保游戏的完整性。使用二进制协议传输数据有助于优化流量,而 unity 中的反应式编程可以轻松同步客户端状态,而无需使用 update() 方法。
这种方法不仅可以提高游戏性能,还可以通过确保所有关键计算都在服务器而不是客户端上执行来增强对作弊的保护。
当然,一如既往地感谢您阅读这篇文章。如果您在组织多人项目架构方面仍有任何疑问或需要帮助 - 我邀请您加入我的 discord
您还可以在我的困境中为我提供很多帮助,并支持发布新文章以及为开发人员免费提供的库和资源:
我的不和谐 | 我的博客 | 我的 github
btc: bc1qef2d34r4xkrm48zknjdjt7c0ea92ay9m2a7q55
eth: 0x1112a2ef850711df4de9c432376f255f416ef5d0
usdt (trc20):trf7sli6trtnau6k3pvvy61bzqkhxdcrlc
今天关于《通过示例在 Unity 和 NodeJS 上的游戏中创建安全、快速的多人游戏》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
php函数版本更新详解和影响分析
- 上一篇
- php函数版本更新详解和影响分析
- 下一篇
- 修复Windows 11上数字键盘不起作用
-
- 文章 · 前端 | 2小时前 | CSS JavaScript localStorage CSS变量 颜色主题切换
- JS动态切换颜色主题方法解析
- 440浏览 收藏
-
- 文章 · 前端 | 2小时前 |
- 响应式设计CSS优化与性能提升
- 447浏览 收藏
-
- 文章 · 前端 | 2小时前 |
- CSS缩放过渡技巧与动画实现
- 450浏览 收藏
-
- 文章 · 前端 | 2小时前 |
- Linux下dmenu快速启动HTML/CSS预览终端
- 306浏览 收藏
-
- 文章 · 前端 | 2小时前 | JavaScript TypeScript 静态类型 泛型 装饰器
- JavaScript与TypeScript类型系统解析
- 141浏览 收藏
-
- 文章 · 前端 | 2小时前 |
- CSSz-index定位解决视频覆盖问题
- 426浏览 收藏
-
- 文章 · 前端 | 2小时前 |
- CSS动画卡顿?transition-transform优化技巧
- 323浏览 收藏
-
- 文章 · 前端 | 3小时前 |
- React条件渲染Props使用技巧详解
- 476浏览 收藏
-
- 文章 · 前端 | 3小时前 | DOMContentLoaded 外部脚本 async/defer 内联script 事件触发
- HTML中运行脚本语言的几种方式详解
- 161浏览 收藏
-
- 文章 · 前端 | 3小时前 |
- JavaScriptpop()方法使用技巧与数组解析
- 148浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3211次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3425次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3454次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4564次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3832次使用
-
- JavaScript函数定义及示例详解
- 2025-05-11 502浏览
-
- 优化用户界面体验的秘密武器:CSS开发项目经验大揭秘
- 2023-11-03 501浏览
-
- 使用微信小程序实现图片轮播特效
- 2023-11-21 501浏览
-
- 解析sessionStorage的存储能力与限制
- 2024-01-11 501浏览
-
- 探索冒泡活动对于团队合作的推动力
- 2024-01-13 501浏览

