Implementation of frame synchronization in Unity3d RTS game

Source: Internet
Author: User
Tags diff random seed unique id

Frame synchronization technology is a kind of synchronization technology used in early RTS games, this article is to introduce the implementation of the frame synchronization in the Rtx game, frame synchronization is a front-end data synchronization method, generally applied to the real-time requirements of the network game, want to learn more frame synchronization knowledge, continue to look down.

A Background

Frame synchronization technology is a kind of synchronization technology used in early RTS games. And state synchronization is different, frame synchronization only synchronous operation, most of its game logic is implemented on the client, the server is mainly responsible for broadcasting and authentication operations, with logic intuitive easy to implement, data volume is small, can be replayed and other advantages.

Some PC games such as Empires, Warcraft 3, StarCraft, and so on, Host (server or a client) only to receive all clients at a certain frame input data, will continue to execute, wait until the timeout to think that the client dropped the line. Obviously, when some clients are unable to upload operational data in time due to network or device problems, it will affect the performance of other clients and cause bad gaming experience. In view of the fair competition of the game, this need to wait for the mechanism is necessary, but does not meet the needs of the hand-travel network environment. To do this, you need to use the "optimistic" mode, that is, the host collects client uploads and broadcasts the received operation data at a fixed frequency, regardless of whether some client's operation data is successfully uploaded, and does not affect the performance of other clients ' games, as shown in 1.

(Fig. 1)

Two Anatomy Unity3d

The core concept of frame synchronization technology is the same input, and the same calculation result is obtained by the same computation process. According to this concept, the following is a brief description of Unity3d implementation of frame synchronization in some aspects of the transformation, Unity3d in the script life cycle Flowchart 2 is shown.

(Fig. 2)

Frame synchronization needs to avoid the use of local timer related values. Therefore, there are several points to note in the process of using Unity3d to achieve frame synchronization:

1. Disable the time class related properties and functions, such as time.deltatime. Use frame time (nth frame X fixed frequency)

2. Disabling functions such as Invoke ()

3. Avoid implementing code that affects game logic in functions such as awake (), Start (), Update (), Lateupdate (), OnDestroy ()

4. Avoid using Unity3d to bring your own physics engine

5. Avoid using the co-coroutine

Three Specific implementation

For the implementation of this article, there are the following definitions:

KeyFrames: Operating data frames that the server broadcasts on a fixed frequency, identified by a unique ID, primarily including client input data or critical information sent by the server (such as a game start or end message)

Fill frame: Due to device performance and network latency, the server broadcast frequency is unlikely to reach the client's update frequency. Using only keyframes to drive the game will cause the game to lag and affect the experience. Therefore, in addition to keyframes, clients need to add several empty data frames themselves to make the game performance smoother

Logical frame Update Time: The time required for the client to execute a frame, which can be dynamically changed based on factors such as device performance and network environment

Server frame Update time: Fixed frequency of server broadcast frame data, usually used for logical calculation of frame interval difference

3.1 Main loop

Frame synchronization requires the same calculation process, which involves two aspects, one is sequential, Unity3d main loop is not controllable, need to customize the game loop, unified management of Game objects and script execution, ensure that all object updates and logical execution sequence exactly. On the other hand, the results are consistent, and the logical computation with floating-point numbers requires special treatment.

classmainloopmanager:monobehaviour{BOOLM_start; intM_logicframedelta;//Logical Frame Update time    intM_logicframeadd;//Cumulative Time     voidLoop () {...//Traverse All Scripts    }     voidUpdate () {if(!M_start)return; if(M_logicframeadd <M_logicframedelta) {M_logicframeadd+= (int) (Time.deltatime * +); }        Else        {            intFramenum =0;  while(Canupdatenextframe () | |Isfillframe ()) {Loop ();//Main Loopframenum++; if(Framenum >Ten)                {                    //play up to 10 frames in a row                     Break; }} M_logicframeadd=0; }    }     BOOLCanupdatenextframe ();//can I update to the next keyframe    BOOLIsfillframe ();//whether the current logical frame is a filled frame}

3.2 Custom Monobehaviour

In the Unity3d script life cycle, some functions, invoke, coroutine call timing are related to local updates and do not satisfy the requirement of frame synchronization mechanism. We implement the above functions and functional requirements by inheriting the Monobehaviour class and have all components involving logical computations inherit the custom class.

 class   custombehaviour:monobehaviour{  bool  M_isdestroy = false  ;  public  bool   Isdestroy { get   {Returnm_isdestroy;}  public  virtual  void   OnDestroy () {};  public  void   Destroy (unityengine.objectobj) {...  //  Destroys the game object  }}  

3.2.1 Update () and Lateupdate ()

From the two aspects of controllability and efficiency, it is not recommended to use one-by-one traversal of the game object to get Custombehaviour to call Update () and Lateupdate (), instead of using a single list to manage.

Delegate voidFrameupdatefunc ();classframeupdate{ Publicframeupdatefunc func;  PublicGameobject ower;  Publiccustombehaviour Behaviour;} classmainloopmanager:monobehaviour{...    List m_frameupdatelist; List M_framelateupdatelist;nn Publicregisterframeupdate (frameupdatefunc func, gameobject owner) Publicunregisterframeupdate (frameupdatefunc func, gameobject owner) Publicregisterframelateupdate (frameupdatefunc func, gameobject owner) Publicunregisterframelateupdate (frameupdatefunc func, gameobject owner)voidLoop () {//Traverse M_frameupdatelist First//and then traverse M_framelateupdatelist .    }    ......}

Take the addition of delete, the component needs to perform update () and lateupdate () dynamic management, in addition to the relative flexibility, but also ensure the efficiency of execution.

3.2.2 Invoke Correlation function

Functions such as Invoke, Invokerepeating, Cancelinvoke, and so on, need to use the reflection mechanism in C # to obtain MethodInfo based on the object objects obj and function name methodname:

var type == type. GetMethod (MethodName);

Through the interface encapsulation, make up the related data (Invokedata), put the list to wait for execution.

 class   invokedata{ public  object   obj;     public   MethodInfo MethodInfo;  public  int      Delaytime;  public  int      repeatrate;  public  int      repeatframeat;  public  bool  iscancel = false  ;}  

As in the above structure, Delaytime is used to record the deferred execution time, repeatrate represents the frequency of repeated calls, repeatframeat marks the frame ordinal of the last call, and the Iscancel tag invoke is canceled. Finally, the call is performed uniformly using MethodBase.Invoke (objectobj, object[] parameters).

class mainloopmanager:monobehaviour{...    List m_invokelist;      void Loop ()    {        // traverse        m_frameupdatelist// re-traverse M_framelateupdatelist         // traverse m_invokelist, and Invoke, Invokerepeating, cancelinvoke}    according to related attributes respectively ......}

3.2.3 co-process Coroutine

The coroutine of the process is more complex, the required situation is less, the scheme of this paper does not realize the coroutine function, but avoids the use.

3.2.4 Destroy related

After destroy the game object or component, OnDestroy () is executed in the next frame. Therefore, you need to take a controlled approach in place of the OnDestroy () function to complete the release of the resource.

classcustombehaviour:monobehaviour{BOOLM_isdestroy =false;  Public BOOLIsdestroy {Set{M_isdestroy =value;} Get{returnM_isdestroy;} }     Public Virtual voidDodestroy () {};  Public voidDestroy (Unityengine.object obj) {if(obj. GetType () = =typeof(Gameobject)) {Gameobject Go=(gameobject) obj; Custombehaviour Behaviours=go.            Getcomponents ();  for(inti =0; I < behaviours. Length; i++) {Behaviours[i]. Isdestroy=true; Behaviours[i].            Dodestroy (); }        }        Else if(obj. GetType () = =typeof(Custombehaviour)) {Custombehaviour behaviour=(custombehaviour) obj; Behaviour. Isdestroy=true; Behaviour.        Dodestroy ();    } UnityEngine.Object.Destroy (obj); }}

3.3 Time class and random number

Frame Sync game Logic all time-related calculations should take the frame time, i.e. the current frame sequence number * Server frame update time/(fill frame number + 1), and each frame random number calculation is controlled by the server seed. As follows:

classmainloopmanager:monobehaviour{ .....intM_serverframedelta;//milliseconds    intM_curframeindex; intM_fillframenum; intM_serverrandomseed;  Public intServerrandomseed {Get{returnM_serverrandomseed;} }     Public intCurframeindex {Get{returnM_curframeindex;} }     Public Static intCurframetime {returnM_curframeindex * M_serverframedelta/(1+m_fillframenum); }     Public Static intDeltaframetime {returnM_serverframedelta/(1+m_fillframenum); }    .......}

Can be written in Custombehaviour, it is convenient to customize the call of the time class, avoid misuse of the Unity3d time class, the same as the random class.

classcustombehaviour:monobehaviour{protected classTime { Public StaticFix Time {Get{return(Fix) Mainloopmanager.curframetime/ +; } }          Public StaticFix deltatime {Get{return(Fix) Mainloopmanager.deltaframetime/ +; } }    }     protected classRandom { Public StaticFix Range (fix min, fix max) {fix diff= max-min; Fix seed=Mainloopmanager.serverrandomseed; returnMin + (int) Fixmath.round (diff * (Seed/ -)); }    }}

Where fix is the fixed-point number, section 3.4 briefly describes how to use the fixed-point number in Unity3d. In this paper, the agreed random seed range is 0-100, and a simple calculation method is adopted. If there is a special need, self-realization.

3.4 Fixed-point number

The client must ensure that the operation process and results of the network frame operations are consistent, however, the different system platforms have a difference in the processing of floating-point numbers, even if the difference is very little, it will cause the "butterfly effect", leading to the emergence of different steps. In most cases, only the fixed-point number of the game object should be modified. Unity3d is not an open-source game engine and cannot modify the position and rotation of the underlying transform. Therefore, the logical layer calculations need to use position and rotation, which are based on the custom fixed-point number, and convert the information obtained after the custom azimuth logic calculation to Unity3d transform before the end of each cycle in order to Unity3d update the presentation layer. The Unity3d Coroutine and Waitforendofframe () are used to meet the above requirements, i.e., the transform and position of the underlying rotation are updated before the Unity3d rendering after the logical layer calculation is complete.

3.5 Network fluctuations

Frame synchronization mechanism, the player input is sent to the network, all responses must wait for the network logical frame to be processed. In the ideal environment, the network frame operation receives the frequency is fixed, can guarantee the client to behave normally not to Dayton. But the truth is, most of the time the network is unstable, and it is difficult to predict when it is fast and slow. The simplest solution is to set up a buffer for the logical frame of the network, setting a buffer upper limit, which is played at a fixed frequency after the number of frames in the buffer is met. If the buffer becomes empty, wait for it to fill up again. By accumulating network logical frame delay, the average distribution to fixed frequency, smooth processing of network fluctuations caused by the lag.

Original address: http://gad.qq.com/article/detail/7195472

Implementation of frame synchronization in Unity3d RTS game

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.