. 虽说多人联机技术已经存在很多年,众多上古游戏就已经支持多人联机,但随着业务复杂度提高,多人联机仍然有许多挖掘空间。从业很多年,参与的项目清一色都是状态同步,相比帧同步,状态同步在同步这件事上并没有多少技术难点,因为实现简单,适用场景众多,很多游戏会采用状态同步,但它并非全能,曾经的MMORPG游戏几乎全是状态同步,因受限于状态同步对于高频率交互实在无能为力,所以只能在游戏设计上彻底放弃了高频率交互。但是行业在发展,玩家的期望值在提升,高频率交互这道坎始终是要迈过去,所以帧同步这项比状态同步更古老的技术近年出现越来越频繁。
. 所谓帧同步,通俗解释就是,严格要求所有客户端每一帧都是同步的(这里的帧指的是逻辑帧而非渲染帧),如何保证这一点呢,原理并不复杂,只要每一帧的输入是一样的,处理过程是一样的,那么结果必然也是一样的。再具体一点,客户端的输入发送到服务端,服务端标记该输入属于哪一帧,随后转发给所有客户端,客户端拿到输入后用同样的逻辑执行,从而得到一样的结果,这就是一帧的处理过程,然后一直重复这一过程。
总结一下,帧同步就是每一帧,输入一致,执行一致,结果一致,不停重复。
浓缩一下,帧同步就是输入一致,执行一致,结果一致。
这看起来非常简单,尝试一下逐个击破。
. 输入是客户端产生的,所有客户端都发送到同一个服务端,服务端维持了一个帧列表,里面记录了每一帧都有哪些输入,然后按需转发给所有客户端,客户端收到的帧数据一致,所以输入也都是一致的。
. 所有客户端都是同一份代码,同样的逻辑,所以执行必然都是一致的。
. 前两项都一致,那么结果是否能一致呢?就好比,输入是【1,1】,处理过程是【加法】,那么【1+1=2】必然成立么,根据常识来看,这必然成立,在计算机中这也必然成立,但是!(“但是”不负众望出现了)如果把【1,1】换成【1.0,1.0】,就变成了【1.0+1.0=2.0】,这在计算机中不一定成立,因为计算机中整数和浮点数的存储方式不一样,计算方式也不一样,浮点数计算是有误差的,误差多少取决于你的CPU,甚至同一个CPU,计算浮点数时也可能有误差,这表面看只是一个【1+1=2】的问题,实际上是个大隐患,误差会像雪球一样越滚越大,从而导致帧同步的结果一团乱。
. 没有完美的方案可以解决这个问题,要为每一个游戏专门定制,才能达到最优效率。
. 例如《王者荣耀》,它的互动频率很高,作为一个竞技游戏,需要客户端严格同步,如何正确帧同步呢?因为浮点数计算精度误差,但整数计算没有精度误差,完全可以把所有的计算都换成整数,把所有浮点数小数点往右挪4位,【1.2345】变成【12345】这不就把问题解决了么?从表现上看,《王者荣耀》的计算逻辑并不会太复杂(其实也有点复杂,只是相对而言),它的计算都在同一个平面,不涉及3D计算,需要计算的内容大致是角色移动,技能命中,涉及到的几何形状大概是直线,圆形,矩形,简单多边形(可能没有),这些几何计算完全可以自己实现,把计算用到的数字全换成整数,从而结果不一致的问题就解决了。
. 上述的解决办法只限于所有的计算过程都由自己掌控的前提下,假设计算过程更复杂,那就不得不使用现成的几何计算库,物理引擎等等外部工具,幸好这种问题早就有人遇到并提供了基于整数计算的物理引擎,或者使用一些开源物理引擎自行换掉浮点数计算的部分。看起来问题已经有完美答案了,但其实不是,设想一下,从此以后数学中只有整数没有小数,这是不是特别扯淡,因为小数是数学不可缺少的一部分,你能用整数取代一部分,但不能完全取代,对物理引擎来说,全部采用整数计算很不科学,性能还会下降,主流物理引擎全部都是浮点数计算,如果坚持采用整数计算,这意味着要放弃所有主流物理引擎,这条道虽然可行,但槽点多多,我觉得这是一条邪道,不归路。
. 现在又陷入了死局,似乎帧同步遇上复杂的数学计算就等于行不通,这就意味着高频率互动的多人游戏没法有复杂的数学计算,但市面上确确实实存在这样的游戏而且非常多,所以其中必然还是有解决方案的,这个方案就是回滚机制,由服务端派发正确的结果,客户端检测到与本地不一致时触发回滚,这样就可以彻底解决结果不一致问题。如何实现回滚机制,这套机制说起来短短几句话,做起来想破脑壳,因为没有一个完美的方案能实现回滚机制,所以针对不同的游戏方案也会有所不同。
. 现在很少有只用帧同步的了,通常都是帧同步为主,状态同步为辅,方可发挥其强大的威力。
. 多人联机没有完美统一的实现方案,会随业务变化而变化,不同的同步频率,不同的同步人数都会直接影响多人联机的落地方案,现在越来越多游戏使用主帧同步辅状态同步的方案,因为帧同步的计算都在客户端,使得客户端对细节可以完全掌控,这一点很重要。
. 在研究帧同步的时候,原本计划实现一个简单的帧同步Demo,结果越写越想写更多,最终做了个动作游戏……(有夸张的成分)
以下是Demo演示
Demo演示-输入延迟
Demo演示-追帧
Demo演示-同步
Demo演示-完整演示
. 不止一次听人质疑帧同步流量消耗大,这大概是帧同步的名字让人产生误解,帧同步每一帧同步的只是输入,数据量极小,讲究高频率,低流量。
. 在制作这个Demo的初期,在如何实现技能这个问题上卡壳了很久,arpg游戏比rpg游戏技能表现复杂的多,在rpg游戏中,技能通常是一个动画几个特效,而arpg中,技能远不止如此,它可以复杂到难以想象,经过深思熟虑,我觉得把技能节点化是一个不错的主意,把功能封装到节点中,节点可接收自定义参数,将节点链接起来就是一个技能。我用Mermaid语法描述节点,因为Mermaid本身就是用于描述流程图的语法,这跟节点化不谋而合(节点连接起来就是流程图),其次Mermaid语法简洁能直接嵌入Markdown实时预览流程图。
以下是技能Atk1的描述信息
Mermaid描述
* 方法: Atk1
* 描述: 平A第一刀
```mermaid
graph TD
转化角色 ==>
播放动画 ==>
等待0[等待] ==>
冲刺 ==>
等待1[等待] ==>
同步 ==>
设置筛选参数 ==>
设置攻击参数 ==>
命中特效 ==>
播放特效 ==>
矩形攻击 ==>
等待2[等待]
播放动画_名字[Atk1] --名字--> 播放动画
播放特效_ID[0] --ID--> 播放特效
命中特效_ID[1] --ID--> 命中特效
等待0_时长[0.2f] --时长--> 等待0
等待1_时长[0.3f] --时长--> 等待1
等待2_时长[0.7f] --时长--> 等待2
冲刺_距离[5.0f] --距离--> 冲刺
冲刺_时长[0.3f] --时长--> 冲刺
设置筛选参数_标识[不同阵营 I 攻方不停顿] --标识--> 设置筛选参数
设置筛选参数_范围[0.5f 0.0f 1.0f 2.2f] --范围--> 设置筛选参数
设置攻击参数_硬直[10] --硬直--> 设置攻击参数
设置攻击参数_血量[20] --血量--> 设置攻击参数
Markdown预览
Runtime生成
public static IEnumerator Atk1(Actor actor, Config.Behavior config)
{
// 0: 转化角色
var self = actor as Role;
var select = self.GetState<Behavior.ParamSelect>();
var attack = new Behavior.ParamAttack() { SelectParam = select };
// 1: 播放动画
Behavior.MetaRoleAnim(self, "Atk1", 0.1f, false);
// 2: 等待0
yield return Tools.Time2Frame(0.2f);
// 3: 冲刺
Behavior.MetaRoleNextF(self, 5.0f, 0.3f);
// 4: 等待1
yield return Tools.Time2Frame(0.3f);
// 5: 同步
Behavior.MetaSyncMove(attack);
// 6: 设置筛选参数
select.Area = Mathm.Quad.New(0.5f, 0.0f, 1.0f, 2.2f);
select.Flags = Const.BehaviorFlag.kSelectXor | Const.BehaviorFlag.kStopMotionNotSender;
// 7: 设置攻击参数
attack.Attack = 20;
attack.Stable = 10;
attack.ForceDuration = 0;
attack.ForceDistance = 0;
attack.StopMotionTime = 0.3f;
// 8: 命中特效
Behavior.MetaEffectHit(attack, config.ID * 10 + 1);
// 9: 播放特效
Behavior.MetaEffect(config.ID * 10 + 0, attack);
// 10: 矩形攻击
{
var __ret__ = Behavior.MetaAttackQuad(attack);
if (__ret__.HasFlag(Const.MetaAttackResult.kAbort))
{
yield break;
}
if (__ret__.HasFlag(Const.MetaAttackResult.kStop))
{
yield return 1;
}
}
// 11: 等待2
yield return Tools.Time2Frame(0.7f);
}
再补充一个-空降我最喜欢的一段
人类生活在充满多样性的世界里。长久以来的研究发现,人类的脑与行为受到基因、环境和文化及其相互作用的塑造,然而这种影响发生的机制始终缺乏系统性探索与研究。近年来,前沿神经影像技术方法飞速进步,推动着多模态脑成像大数据集的产生和融合性探索,并让学界得以深入探究人脑宏观结构与功能连接组架构,为包括上述主题在内的许多有趣而重要的科学问题带来了新的启发和思路。2022年12月20日,北京大学物理学院、IDG麦戈文脑科学研究所高家红团队在《NatureNeuroscience》在线发表了题为“IncreasingdiversityinconnectomicswiththeChineseHumanConne
导读:随着智能设备的普及,手机游戏逐渐占据整个游戏市场的大头。伴随着手机游戏的风靡,外挂也将其邪恶的触手伸向了这一领域,反外挂的战场从PC端蔓延到了移动端。由于移动设备与PC终端之间天然存在的巨大差异,外挂的类型也存在较大差异,主要外挂类型也不尽相同。模拟点击外挂正是手游领域占比极大的外挂类型之一。通过外挂来模拟真人玩家在手机上的操作,自动化进行游戏,攫取游戏资源,扰乱正常健康的游戏秩序,这就是“模拟点击”外挂及其危害。本文介绍了智企GAMEAI检测模拟点击异常行为的AI方案,综合“卷积熵”、“图学习”、“对比学习”等算法思想,对“点击序列”进行数据建模,构建监督、无监督算法模型,检测玩家是否
我正在开发一款多人游戏,但我在同步玩家时遇到了问题。当玩家按下其中一个移动键(W、A、S、D)时,客户端会发送一个关于按下按钮的数据包,服务器会根据按下的键设置速度,并向所有附近的玩家发回新速度。当玩家释放按键时,客户端发送一个数据包,服务器将玩家速度设置为0,0,并将位置和速度发送给附近的所有玩家。所以问题是当我释放按键时,大部分时间播放器会跳回。我该如何解决这个问题?我正在使用socket.io。客户端:socket.on('positionEntity',function(data){console.log((data.x-entities[data.id].x)+""+(dat
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭3年前。Improvethisquestion我有兴趣制作某种多人Angular色扮演游戏,作为一种纯粹基于浏览器的游戏,几乎没有或没有插件要求。经过大量研究,我得出了以下计划。我知道我在这里引用的某些技术并未在所有浏览器(特别是IE)中采用,但我暂时愿意接受。另外-我知道MMO在任何情况下都是一个值得为之奋斗的崇高目标,但过去我在类似的方向上做过很多较小的项目,我觉得我想好好尝试一下终于。所以这是一个粗略的概述,我很想听听任何人都可
这里是新手。我正在使用Phaser,特别是等距插件。我想知道是否可以在Phaser中创建类似于agar.io的游戏,在处理实时多重连接方面,生成一张包含大约300名玩家的巨大map,所有这些都不会对游戏性能产生太大影响。我真的不知道如何处理多人游戏部分(可能是套接字,node.js)才能让它工作得很好。至于生成一个非常大的map,我也很空白。是否有可能在Phaser中创建一个等距类型的游戏来处理多个实时多人游戏和当用户到达可见“map”的边缘时生成的巨大map?如何?如果不是,我应该选择什么(js和其他应用程序中的游戏引擎)来实现我想要的? 最佳答案
摘要【目的】本文针对东数西算背景下的算网运营体系建设方案进行探索,介绍了算网运营体系包含的“算力一体供给、算力一站式服务、算力可信交易”三个核心体系的能力建设,提出了基于区块链的“身份、协议、订单、账单、佣金”五信交易模型。 【方法】本文从算力提供、算力交易、算力使用、交易安全等方面出发,阐述了多方协同供给算力机制、算网产品体系和售卖模式、算网业务使用方式和算网可信交易支撑方式。 【结果】基于区块链技术的“三体五信”算网运营体系,具备多方算力汇聚、算网融合、共享交易的能力,具备交易主体身份可信、交易主体协议可信、交易过程订单可信、交易分成佣金可信、交易结果账单可信的可靠保障。 【局限】算力交易
文章目录2023年四川大学图情档研究生入学考试专业课真题回忆版667信息管理基础名词解释(25分)简答题(25分)分析题(100分)972信息检索辨析题(25分)简答题(45分)分析题(80分)2023年四川大学图情档研究生入学考试专业课真题回忆版667信息管理基础名词解释(25分)实得信息信息采准率信息需求信息分化开放存取简答题(25分)简述信息资源的基本特征说明信息资源质量不高的原因列举两个信息社会理论简述知识结构体系结构的特点数字图书馆有哪些发展新趋势?分析题(1
1)在下面的代码中,使gameOfLive成为变量而不仅仅是functiongameOfLife()背后的原因是什么?2)什么是gol?它看起来像一个数组,但我不熟悉语法或它的名称。我正在研究http://sixfoottallrabbit.co.uk/gameoflife/if(!window.gameOfLife)vargameOfLife=function(){vargol={body:null,canvas:null,context:null,grids:[],mouseDown:false,interval:null,control:null,moving:-1,clickT
我有一个简单的程序,可以生成随机字符串和数字并将其放入特定格式:输出:A=SKEK673KJKB=67235C=PDCNE39JSWL我有4个函数,包括main:funcgenRandInt()string{//returnstring(randInt)}funcgenRandStr()string{//return(randStr)}funcgenFakeData()string{fmt.Println("A="+genRanStr()+genRandInt().....etc)}funcmain(){genFackeData()}到目前为止程序运行良好,我通过bash循环执行它以便
文章目录一、前言二、思考问题与解决方案1、思考问题2、解决方案2.1、Unity中如何开启摄像头并对图像进行采样2.2、图像如何中转给其他客户端2.3、如何实现清晰度切换2.4、客户端如何对图像进行解码并显示三、实际操作0、思维导图1、界面设计与制作2、UI素材获取3、创建Unity工程4、制作UI界面5、下载Mirror网络插件6、写C#代码6.1、网络管理器:VideoChatNetwork.cs6.2、摄像头画面:Player.cs6.3、业务逻辑:MainLogic.cs6.4、界面交互:MainPanel.cs7、挂脚本7.1、VideoChatNetwork脚本7.2、Player