Synchronizer
Synchronizer is a prediction class, used to synchronize variable over network. 3 synchronizer is implemented:
- Fload
- Vector2
- Vector3
SynchedValue interface
Lerps
AccLerp
: Acceleration lerp. Lerp when value changes.DecLerp
: Deceleration lerp. Lerp to its current value.
Slip
Value follows a virtual point to smooth the value changes. The slip is the lerp between the current value and the followed value.
Values
CurrentValue
: The last predicted value (red point)Value
: Current smoothed value (blue point)NextValue
: Predicted next frame value (purple point)
Update value
AddValue(value)
: Simple addInitValue(value)
: Resets all and initializes valueUpdate(ping, accuracy)
: This function must be called at each frame. Sets the ping and accuracy. If there is distance between current position and target position < accuracy, Value is not updated.HandlePosition(value)
: Current position of the object reference. Can be called from time to time. This applies a fix on value.HandleDirection(value)
: Direction. Called this whenever the direction (or speed) changes.
Vector specifics
CurrentDirection
: Gets the current directionAngleAxis
: Gets the current QuaternionRotate(transform, lerp)
: Applies the current rotation to transform
Example
- Create 2 cubes and set this behaviour on the first.
- Set the second in Child variable
- Play and move with keyboard arrows
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using SynchedVector3 = EODE.Wonderland.Net.SynchedVector3;
public class TestSynchedVar : MonoBehaviour {
const float _speed = 5f;
public Transform Child;
public float Ping = 0.1f;
SynchedVector3 _sync = new SynchedVector3();
Vector3 _direction = new Vector3();
void Awake() {
_sync.InitValue(transform.localPosition);
}
void Start() {
StartCoroutine(UpdatePositionRoutine());
}
void Update() {
var currentAxis = GetAxis();
if (_prevAxis != currentAxis) {
_prevAxis = currentAxis;
_direction = currentAxis;
SendDirection().WrapErrors();
}
transform.localPosition += currentAxis * Time.deltaTime;
if (_direction != Vector3.zero) transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.FromToRotation(Vector3.up, _direction), 0.2f);
_sync.Update(Ping);
Child.localPosition = _sync.Value;
if (_sync.CurrentDirection != Vector3.zero) _sync.Rotate(Child);
}
IEnumerator UpdatePositionRoutine() {
while (true) {
yield return new WaitForSeconds(1f);
SendPosition().WrapErrors();
}
}
async Task SendPosition() {
var pos = transform.position;
await new WaitForSeconds(Ping);
_sync.HandlePosition(pos);
}
async Task SendDirection() {
var dir = _direction;
await new WaitForSeconds(Ping);
_sync.HandleDirection(dir);
}
public Vector3 GetAxis() {
Vector3 axis = new Vector3(
(Input.GetKey(KeyCode.RightArrow) ? 1f : 0f) + (Input.GetKey(KeyCode.LeftArrow) ? -1f : 0f),
(Input.GetKey(KeyCode.UpArrow) ? 1f : 0f) + (Input.GetKey(KeyCode.DownArrow) ? -1f : 0f),
0f
);
if (Mathf.Abs(axis.x) + Mathf.Abs(axis.y) > 1f) {
axis.x *= 0.68f;
axis.y *= 0.68f;
}
return axis * _speed;
}
Vector3 _prevAxis = Vector3.zero;
}