Unity3D实现帧同步技术

在竞技类网络游戏比较火,市面上也出现了很多这种类型的游戏竞赛,提到网络游戏就回避不了一个问题:同步技术,多个人在一个游戏场景围攻一个怪物或者说多人组队战斗等等。

状态同步

现在在移动端的游戏由于带宽的限制,一般采用实时同步的方式是状态同步,也就是说角色的状态发生改变,才会去发送消息。举个例子:

3D角色一般的动作状态有:Idle,walk,run,attack等,玩家操作键盘或者触摸屏按钮,会触发这些动作,一个游戏场景中会有多个角色,每个角色都有自己的动作状态,为了让玩家能够看到其他玩家在做什么,需要同步,玩家默认状态是idle,玩家刚出现时是idle状态,这个时候,客户端会把玩家的状态,位置,方向传送给服务器,其他玩家也是一样的,服务器接收到信息后,会把这些信息发送给除了它本人之外的其它玩家,这样我们就可以看到其他玩家的状态了。如果玩家从idle状态转化到walk状态,这表明玩家的动作状态发生了变化,这也需要将信息发给服务器,服务器进行群发给其他玩家,这样其他玩家就可以看到角色开始walk了。接下来如果玩家继续走,客户端就不发送消息给服务器了,因为状态没发生变化,等状态再变化时才会发送消息给服务器,然后服务器再群发消息,在此过程中,其他客户端会通过插值的方式把两个状态之间的距离实现出来,以此类推。。。。。。这就是所说的状态同步模式。

帧同步模式

帧同步含义游戏客户端接受来自网络的多个客户端的操作,如果这些操作在各个客户端是一样的,那么多个客户端的显示也就一样了,这就带来了“同步”的效果。所以在这种情况下,各个客户端的运算要绝对一致,不能依赖诸如本地时间、本地随机数等等“输入”,而要一切以网络来的操作数据为主。

一般来说,大多数的游戏客户端引擎,都会定时调用一个接口函数,这个函数由用户填写内容,用来修改和控制游戏中各种需要显示的内容。比如在在Unity里面叫Update(),这类函数通常会在每帧画面渲染前调用,当用户修改了游戏中的各个角色的位置、大小后,就在下一帧画面中显示出来。而在帧同步的游戏中,这个Update()函数依然是存在,只不过里面大部分的内容,需要挪到另外一个类似的函数中,我们可以称之为UpdateNet()函数——由网络层不断的接收服务器发来的“网络帧”数据包,每收到一个这样的数据包,就调用一次这个UpdateNet()函数,这样游戏就从通过本地CPU的Update()函数的驱动,改为根据网络来的UpdateNet()函数驱动了。显然,网络发过来的同步帧速度会明显比本地CPU要慢的多,这里就对我们的游戏逻辑开发提出了更高的要求——如何同步的同时,还能保证流畅?

实现UpdateNet函数内容,其实就是定义一个堆栈用于存放网络发过来的消息,通过帧监测将其数据拿出来使用,因为Update函数明显比UpdateNet快的多,这就需要我们定义一个时间间隔用于消息的发送,比如50毫秒或者100毫米等。

private float AccumilatedTime = 0f;

private float FrameLength = 0.05f; //50 miliseconds   
//called once per unity frame   
public void Update()
{
    //Basically same logic as FixedUpdate, but we can scale it by adjusting FrameLength   
    AccumilatedTime = AccumilatedTime + Time.deltaTime;

    //in case the FPS is too slow, we may need to update the game multiple times a frame   
    while (AccumilatedTime > FrameLength)
    {
        GameFrameTurn();
        AccumilatedTime = AccumilatedTime - FrameLength;
    }
}
private void GameFrameTurn()
{
    //first frame is used to process actions   
    if (GameFrame == 0)
    {
        if (LockStepTurn())
        {
            GameFrame++;
        }
    }
    else
    {
        //update game   
        SceneManager.Manager.TwoDPhysics.Update(GameFramesPerSecond);

        List<IHasGameFrame> finished = new List<IHasGameFrame>();
        foreach (IHasGameFrame obj in SceneManager.Manager.GameFrameObjects)
        {
            obj.GameFrameTurn(GameFramesPerSecond);
            if (obj.Finished)
            {
                finished.Add(obj);
            }
        }

        foreach (IHasGameFrame obj in finished)
        {
            SceneManager.Manager.GameFrameObjects.Remove(obj);
        }

        GameFrame++;
        if (GameFrame == GameFramesPerLocksetpTurn)
        {
            GameFrame = 0;
        }
    }
}

帧同步游戏中,由于需要“每一帧”都要广播数据,所以广播的频率非常高,这就要求每次广播的数据要足够的小。最好每一个网络帧,能在一个MTU以下,这样才能有效降低底层网络的延迟。同样的理由,我们为了提高实时性,一般也倾向于使用UDP而不是TCP协议,这样底层的处理会更高效。但是,这样也会带来了丢包、乱序的可能性。因此我们常常会以冗余的方式——比如每个帧数据包,实际上是包含了过去2帧的数据,也就是每次发3帧的数据,来对抗丢包。也就是说三个包里面只要有一个包没丢,就不影响游戏。

帧同步实现的过程有个很重要的地方就是逻辑层和表现层一定要分开,表现层先行,逻辑层等发到服务端的指令再处理。帧与帧之间的播放频率,则由服务器统一控制,但由于网络抖动等影响,帧的频率并不是太稳定,为避免播放抖动,帧数控制器需要进行一定的平滑处理。

image

网络抖动的产生原因:在网络游戏中,各个客户端的运行条件和环境往往千差万别,有的硬件好一些,有的差一些,各方的网络情况也不一致;时不时玩家的网络还会在游戏过程中,发生临时的拥堵,我们称之为“网络抖动”。可能导致客户端收到“过去时间”里的一堆网络帧,客户端需要拿出一定的时间去处理这些堆积的网络帧,因此,客户端必须要有处理这些堆积起来的网络数据的能力。

实时同步游戏最重要的是流畅,然而影响游戏流畅的因素很多,网络带宽的限制,CPU运算和渲染效率的限制。一般玩家控制的角色的动作,包括当前客户端控制的角色,还是应该从网络帧里面获得行为数据,因为如果玩家爱控制角色不一致的太多,整个游戏场面就会差更多。很多游戏中的怪物AI都是根据玩家角色来设定的,所以一旦玩家角色的行为是同步的,那么大多数的怪物的表现还是一致的。

帧同步游戏技术,并不存在一种可以让游戏流畅的通用做法,而是需要和游戏具体做很多结合,在减少数据包,优化游戏快进体验,控制发包速度上尽量调优。同时还需要和游戏产品策划一起,平衡一致性、实时性、公平性的策略,才能真正达到流畅游戏的目的。

链接
demo下载地址
关于帧同步和网游游戏开发的一些心得

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343