Initial
This commit is contained in:
commit
36a53f343e
1 changed files with 300431 additions and 0 deletions
292
UnityProject/Assets/Scripts/CarClient.cs
Normal file
292
UnityProject/Assets/Scripts/CarClient.cs
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
[NetworkSettings(channel = 0, sendInterval = 0)]
|
||||
public class CarClient : NetworkBehaviour {
|
||||
|
||||
public float delay = 2;
|
||||
|
||||
private float timeAlive = 0;
|
||||
private StateBuffer stateBuffer;
|
||||
|
||||
public GameObject brakeLights;
|
||||
public Transform explosion;
|
||||
public Transform fire;
|
||||
|
||||
private Transform thisFire;
|
||||
|
||||
private bool alreadyOnFire = false;
|
||||
private bool isDead = false;
|
||||
|
||||
private void Start ()
|
||||
{
|
||||
if (isClient)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void FixedUpdate ()
|
||||
{
|
||||
if(isClient)
|
||||
{
|
||||
if(stateBuffer == null)
|
||||
stateBuffer = new StateBuffer(delay);
|
||||
|
||||
if (stateBuffer.CanStartInterpolating())
|
||||
{
|
||||
//Pontosabb, mint a Time.time
|
||||
timeAlive += Time.deltaTime;
|
||||
|
||||
|
||||
stateBuffer.Interpolate(timeAlive);
|
||||
|
||||
if (isDead)
|
||||
{
|
||||
transform.position = Vector3.zero;
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeBrakeLights(stateBuffer.IsBraking());
|
||||
|
||||
if(stateBuffer.ShouldExplode() && !alreadyOnFire)
|
||||
{
|
||||
thisFire = Instantiate(fire, transform.position, transform.rotation);
|
||||
alreadyOnFire = true;
|
||||
}
|
||||
|
||||
if (stateBuffer.ShouldDie())
|
||||
{
|
||||
Instantiate(explosion, transform.position, transform.rotation);
|
||||
Destroy(thisFire.gameObject);
|
||||
isDead = true;
|
||||
}
|
||||
|
||||
transform.position = stateBuffer.GetCurrentPosition();
|
||||
transform.rotation = stateBuffer.GetCurrentRotation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//A féklámpa ki/be kapcsolására
|
||||
private void ChangeBrakeLights (bool newState)
|
||||
{
|
||||
for (int a = 0; a < brakeLights.transform.childCount; a++)
|
||||
brakeLights.transform.GetChild(a).gameObject.SetActive(newState);
|
||||
}
|
||||
|
||||
//RPC: Remote procedure call, QoS: reliable sequenced
|
||||
[ClientRpc(channel = 0)]
|
||||
public void RpcDecodeBits (ulong newStateBits)
|
||||
{
|
||||
CompressedStateFrame compressedStateFrame = new CompressedStateFrame(newStateBits);
|
||||
StateFrame newStateFrame = compressedStateFrame.GetDecodedStateFrame(transform);
|
||||
stateBuffer.AddFrame(ref newStateFrame);
|
||||
}
|
||||
}
|
||||
|
||||
public class CompressedStateFrame
|
||||
{
|
||||
private ulong stateBits;
|
||||
public CompressedStateFrame(ulong stateBits)
|
||||
{
|
||||
this.stateBits = stateBits;
|
||||
}
|
||||
|
||||
public StateFrame GetDecodedStateFrame(Transform carTransform)
|
||||
{
|
||||
StateFrame decodedFrame = new StateFrame();
|
||||
|
||||
decodedFrame.isBraking = TakeAwayLastBitAsBool();
|
||||
|
||||
float xPosition = TakeAwayLastNbitsAsFixed(12, 1f / 16);
|
||||
float zPosition = TakeAwayLastNbitsAsFixed(12, 1f / 16);
|
||||
decodedFrame.position = new Vector3(xPosition, carTransform.position.y, zPosition);
|
||||
|
||||
float rotation = TakeAwayLastNbitsAsFixed(7, 360f / 127);
|
||||
decodedFrame.direction = Quaternion.AngleAxis(rotation, carTransform.up);
|
||||
|
||||
decodedFrame.shouldExplode = TakeAwayLastBitAsBool();
|
||||
decodedFrame.shouldDie = TakeAwayLastBitAsBool();
|
||||
decodedFrame.isTurning = TakeAwayLastBitAsBool();
|
||||
|
||||
decodedFrame.serverStartTime = (float)stateBits / 1000;
|
||||
|
||||
return decodedFrame;
|
||||
}
|
||||
|
||||
private bool TakeAwayLastBitAsBool ()
|
||||
{
|
||||
bool lastBit = ( stateBits & 1 ) == 1;
|
||||
stateBits >>= 1;
|
||||
return lastBit;
|
||||
}
|
||||
private float TakeAwayLastNbitsAsFixed (int n, float multiplier)
|
||||
{
|
||||
return (float)TakeAwayLastNbitsAsUlong(n) * multiplier;
|
||||
}
|
||||
private ulong TakeAwayLastNbitsAsUlong (int n)
|
||||
{
|
||||
ulong mask = (ulong)( 1 << n ) - 1;
|
||||
ulong lastNbits = stateBits & mask;
|
||||
stateBits >>= n;
|
||||
return lastNbits;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Egy autó egy állapota, tekinthetőek keyframeeknek, amik között lineárisan készítünk kitöltő állapotokat készítünk
|
||||
[System.Serializable]
|
||||
public class StateFrame
|
||||
{
|
||||
//client mikor kezdte el?
|
||||
public float clientStartTime;
|
||||
//szerver mikor kezdte el?
|
||||
public float serverStartTime;
|
||||
//Az időket az adott autó spawnolásától mérjük.
|
||||
|
||||
public Vector3 position;
|
||||
public Quaternion direction;
|
||||
|
||||
public bool isBraking;
|
||||
public bool isTurning;
|
||||
public bool shouldExplode;
|
||||
public bool shouldDie;
|
||||
}
|
||||
|
||||
//Az autó állapotframejei itt tárolódnak
|
||||
[System.Serializable]
|
||||
public class StateBuffer
|
||||
{
|
||||
private float timeOfLastUpdate;
|
||||
|
||||
private float delay;
|
||||
|
||||
private float intervalLengthClient;
|
||||
private float intervalLengthServer;
|
||||
private float qBetweenFrames;
|
||||
|
||||
private bool isInValidState = true;
|
||||
|
||||
private bool hasStarted = false;
|
||||
|
||||
//jelenleg ez a két frame közt van
|
||||
private StateFrame before;
|
||||
private StateFrame after;
|
||||
//Egy autó jövője delay mp-re előre
|
||||
private Queue next;
|
||||
|
||||
public StateBuffer (float delay)
|
||||
{
|
||||
this.delay = delay;
|
||||
next = new Queue();
|
||||
}
|
||||
|
||||
public void AddFrame (ref StateFrame newFrame)
|
||||
{
|
||||
//A visszajátszás sebessége kiszámolásáshoz fontos tudni
|
||||
timeOfLastUpdate = newFrame.serverStartTime;
|
||||
|
||||
if (before == null)
|
||||
{
|
||||
before = newFrame;
|
||||
before.clientStartTime = 0;
|
||||
}
|
||||
|
||||
else if (after == null)
|
||||
after = newFrame;
|
||||
else
|
||||
next.Enqueue(newFrame);
|
||||
}
|
||||
|
||||
public bool CanStartInterpolating ()
|
||||
{
|
||||
if (before != null && after != null)
|
||||
hasStarted = true;
|
||||
return hasStarted;
|
||||
}
|
||||
|
||||
public void Interpolate (float timeAlive)
|
||||
{
|
||||
do
|
||||
{
|
||||
isInValidState = true;
|
||||
|
||||
intervalLengthClient = timeAlive - before.clientStartTime;
|
||||
intervalLengthServer = after.serverStartTime - before.serverStartTime;
|
||||
|
||||
CompansateIfOutOfSync();
|
||||
|
||||
if (NeedToChangeFrame())
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
ChangeFrame(timeAlive);
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
isInValidState = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} while (NeedToChangeFrame());
|
||||
|
||||
qBetweenFrames = intervalLengthClient / intervalLengthServer;
|
||||
}
|
||||
|
||||
private void CompansateIfOutOfSync()
|
||||
{
|
||||
intervalLengthServer /= ( timeOfLastUpdate - before.serverStartTime ) / delay;
|
||||
}
|
||||
private bool NeedToChangeFrame()
|
||||
{
|
||||
return intervalLengthClient > intervalLengthServer || intervalLengthServer == 0;
|
||||
}
|
||||
|
||||
private void ChangeFrame (float timeAlive)
|
||||
{
|
||||
before = after;
|
||||
before.clientStartTime = timeAlive - ( intervalLengthClient - intervalLengthServer );
|
||||
after = (StateFrame)next.Dequeue();
|
||||
}
|
||||
|
||||
public bool ShouldExplode()
|
||||
{
|
||||
return before.shouldExplode;
|
||||
}
|
||||
public bool ShouldDie()
|
||||
{
|
||||
return before.shouldDie;
|
||||
}
|
||||
public bool IsBraking ()
|
||||
{
|
||||
return before.isBraking;
|
||||
}
|
||||
public Vector3 GetCurrentPosition()
|
||||
{
|
||||
if (!isInValidState) return Vector3.zero;
|
||||
|
||||
if (Vector3.Magnitude(after.position - before.position) > 20)
|
||||
{
|
||||
Debug.Log("jump " + before.position + ", " + after.position);
|
||||
return after.position;
|
||||
}
|
||||
|
||||
if (before.isTurning)
|
||||
return Vector3.Slerp(before.position, after.position, qBetweenFrames);
|
||||
else
|
||||
return Vector3.Lerp(before.position, after.position, qBetweenFrames);
|
||||
}
|
||||
|
||||
public Quaternion GetCurrentRotation()
|
||||
{
|
||||
if (!isInValidState) return Quaternion.identity;
|
||||
return Quaternion.Slerp(before.direction, after.direction, qBetweenFrames);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in a new issue