Guest User

Untitled

a guest
Feb 23rd, 2017
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.40 KB | None | 0 0
  1.  
  2. using System;
  3. using System.Collections;
  4. using UnityEngine;
  5.  
  6. // This script is used to interpolate and predict values to make the position smooth
  7. // And correspond to the real one.
  8. public class NetworkTransformInterpolation : MonoBehaviour
  9. {
  10.     public enum InterpolationMode {
  11.         INTERPOLATION,
  12.         EXTRAPOLATION
  13.     }
  14.    
  15.     public InterpolationMode mode = InterpolationMode.INTERPOLATION;
  16.    
  17.     private double interpolationBackTime = 200;
  18.    
  19.     // The maximum time we try to extrapolate
  20.     private float extrapolationForwardTime = 1000; // Can make this depend on ping if needed
  21.        
  22.     private bool running = false;
  23.    
  24.     // We store twenty states with "playback" information
  25.     NetworkTransform[] bufferedStates = new NetworkTransform[20];
  26.     // Keep track of what slots are used
  27.     int statesCount = 0;
  28.    
  29.     // We call it on remote player to start receiving his transform
  30.     public void StartReceiving() {
  31.         running = true;
  32.     }
  33.    
  34.     public void ReceivedTransform(NetworkTransform ntransform) {
  35.         if (!running) return;
  36.        
  37.         // When receiving, buffer the information
  38.         // Receive latest state information
  39.         Vector3 pos = ntransform.Position;
  40.         Quaternion rot = ntransform.Rotation;
  41.                        
  42.         // Shift buffer contents, oldest data erased, 18 becomes 19, ... , 0 becomes 1
  43.         for ( int i=bufferedStates.Length-1;i>=1;i-- ) {
  44.             bufferedStates[i] = bufferedStates[i-1];
  45.         }
  46.          
  47.         // Save currect received state as 0 in the buffer, safe to overwrite after shifting
  48.         bufferedStates[0] = ntransform;
  49.        
  50.         // Increment state count but never exceed buffer size
  51.         statesCount = Mathf.Min(statesCount + 1, bufferedStates.Length);
  52.  
  53.         // Check integrity, lowest numbered state in the buffer is newest and so on
  54.         for (int i=0; i<statesCount-1; i++) {
  55.             if (bufferedStates[i].TimeStamp < bufferedStates[i+1].TimeStamp) {
  56.                 Debug.Log("State inconsistent");
  57.             }
  58.         }
  59.     }
  60.    
  61.  
  62.     // This only runs where the component is enabled, which is only on remote peers (server/clients)
  63.     void Update() {
  64.         if (!running) return;
  65.         if (statesCount == 0) return;
  66.        
  67.         UpdateValues();
  68.        
  69.         double currentTime = TimeManager.Instance.NetworkTime;
  70.         double interpolationTime = currentTime - interpolationBackTime;
  71.        
  72.         // We have a window of interpolationBackTime where we basically play
  73.         // By having interpolationBackTime the average ping, you will usually use interpolation.
  74.         // And only if no more data arrives we will use extrapolation
  75.        
  76.         // Use interpolation
  77.         // Check if latest state exceeds interpolation time, if this is the case then
  78.         // it is too old and extrapolation should be used
  79.         if (mode == InterpolationMode.INTERPOLATION && bufferedStates[0].TimeStamp > interpolationTime) {
  80.             for (int i=0;i < statesCount; i++) {
  81.                 // Find the state which matches the interpolation time (time+0.1) or use last state
  82.                 if (bufferedStates[i].TimeStamp <= interpolationTime || i == statesCount-1) {
  83.                     // The state one slot newer (<100ms) than the best playback state
  84.                     NetworkTransform rhs = bufferedStates[Mathf.Max( i-1, 0 )];
  85.                     // The best playback state (closest to 100 ms old (default time))
  86.                     NetworkTransform lhs = bufferedStates[i];
  87.                    
  88.                     // Use the time between the two slots to determine if interpolation is necessary
  89.                     double length = rhs.TimeStamp - lhs.TimeStamp;
  90.                     float t = 0.0F;
  91.                     // As the time difference gets closer to 100 ms t gets closer to 1 in
  92.                     // which case rhs is only used
  93.                     if (length > 0.0001) {
  94.                         t = (float)((interpolationTime - lhs.TimeStamp) / length);
  95.                     }
  96.                    
  97.                     // if t=0 => lhs is used directly
  98.                     transform.position = Vector3.Lerp(lhs.Position, rhs.Position, t);
  99.                     transform.rotation = Quaternion.Slerp(lhs.Rotation, rhs.Rotation, t);
  100.                     return;
  101.                 }
  102.             }
  103.         }
  104.         else {
  105.             // If the value we have is too old, use extrapolation based on 2 latest positions
  106.             float extrapolationLength = Convert.ToSingle(currentTime - bufferedStates[0].TimeStamp)/1000.0f;
  107.             if (mode == InterpolationMode.EXTRAPOLATION && extrapolationLength < extrapolationForwardTime && statesCount>1) {
  108.                 Vector3 dif = bufferedStates[0].Position - bufferedStates[1].Position;
  109.                 float distance = Vector3.Distance(bufferedStates[0].Position, bufferedStates[1].Position);
  110.                 float timeDif = Convert.ToSingle(bufferedStates[0].TimeStamp - bufferedStates[1].TimeStamp)/1000.0f;
  111.                
  112.                 if (Mathf.Approximately(distance, 0) || Mathf.Approximately(timeDif, 0)) {
  113.                     transform.position = bufferedStates[0].Position;
  114.                     transform.rotation = bufferedStates[0].Rotation;
  115.                     return;
  116.                 }
  117.                        
  118.                 float speed = distance / timeDif;
  119.                
  120.                 dif = dif.normalized;
  121.                 Vector3 expectedPosition = bufferedStates[0].Position + dif * extrapolationLength * speed;
  122.                 transform.position = Vector3.Lerp(transform.position, expectedPosition, Time.deltaTime*speed);
  123.             }
  124.             else {
  125.                 transform.position = bufferedStates[0].Position;
  126.             }
  127.                    
  128.             // No extrapolation for the rotation
  129.             transform.rotation = bufferedStates[0].Rotation;
  130.         }
  131.     }
  132.    
  133.     private void UpdateValues() {
  134.         double ping = TimeManager.Instance.AveragePing;
  135.         if (ping < 50) {
  136.             interpolationBackTime = 50;
  137.         }
  138.         else if (ping < 100) {
  139.             interpolationBackTime = 100;
  140.         }
  141.         else if (ping < 200) {
  142.             interpolationBackTime = 200;
  143.         }
  144.         else if (ping < 400) {
  145.             interpolationBackTime = 400;
  146.         }
  147.         else if (ping < 600) {
  148.             interpolationBackTime = 600;
  149.         }
  150.         else {
  151.             interpolationBackTime = 1000;
  152.         }
  153.     }
  154.    
  155. }
Add Comment
Please, Sign In to add comment