- Home /
I made a noobish mistake (explained in my last comment) which is now fixed.
Unity Networking. Player flickers.
Hey. I'm currently trying to get rid of a little problem i have with my Multiplayer FPS. When i use only NetworkViews to synchronize the position of the Player between all connected players, the Player-Gameobjects of the other players kind of flicker when they move. That's why i added the NetworkInterpolatedTransfom Script from the Networking example to every Gameobject which has a NetworkView attached to it. When a game started i execute this code snippet in another script:
function Start () {
if(!networkView.isMine){
var interpscript : NetworkInterpolatedTransform = GetComponent("NetworkInterpolatedTransform");
interpscript.enabled = true;
transform.networkView.observed = interpscript;
}
}
With this code i activate the NetworkInterpolatedTransform-Script and set the observed value of the networkview to this script on every gameobject i added this Script before.
The result of this can be seen in this Web Demo: http://dl.dropbox.com/u/83937500/WebPlayerBuild.html
(How to play:Open it in 2 BrowserWindows, type in a Name, click on advanced, click on start hosting a server, then test , then Start Server. In the other window just click on advanced and your server should show up in the Join a game via the list window)(Btw. Models/Animation/... are just for testing)
As you can hopefully see: There is a some type of flickering in the direction where the player moves. The Player himself is not flickering at all.
Now my question is: Where does this problem possible comes from and how can i solve it if someone knows how?
If you don't know the NetworkInterpolatedTransform-Script and need to see it to answer the question i can post it here.
Thanks in advance, ExTheSea.
PS: Here is the NetworkInterpolatedTransform.cs because i saw that the Networking example isn't available anymore for some reason:
using UnityEngine;
using System.Collections;
public class NetworkInterpolatedTransform : MonoBehaviour {
public double interpolationBackTime = 0.1;
internal struct State
{
internal double timestamp;
internal Vector3 pos;
internal Quaternion rot;
}
// We store twenty states with "playback" information
State[] m_BufferedState = new State[20];
// Keep track of what slots are used
int m_TimestampCount;
void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
// Always send transform (depending on reliability of the network view)
if (stream.isWriting)
{
Vector3 pos = transform.localPosition;
Quaternion rot = transform.localRotation;
stream.Serialize(ref pos);
stream.Serialize(ref rot);
}
// When receiving, buffer the information
else
{
// Receive latest state information
Vector3 pos = Vector3.zero;
Quaternion rot = Quaternion.identity;
stream.Serialize(ref pos);
stream.Serialize(ref rot);
// Shift buffer contents, oldest data erased, 18 becomes 19, ... , 0 becomes 1
for (int i=m_BufferedState.Length-1;i>=1;i--)
{
m_BufferedState[i] = m_BufferedState[i-1];
}
// Save currect received state as 0 in the buffer, safe to overwrite after shifting
State state;
state.timestamp = info.timestamp;
state.pos = pos;
state.rot = rot;
m_BufferedState[0] = state;
// Increment state count but never exceed buffer size
m_TimestampCount = Mathf.Min(m_TimestampCount + 1, m_BufferedState.Length);
// Check integrity, lowest numbered state in the buffer is newest and so on
for (int i=0;i<m_TimestampCount-1;i++)
{
if (m_BufferedState[i].timestamp < m_BufferedState[i+1].timestamp)
Debug.Log("State inconsistent");
}
//Debug.Log("stamp: " + info.timestamp + "my time: " + Network.time + "delta: " + (Network.time - info.timestamp));
}
}
// This only runs where the component is enabled, which is only on remote peers (server/clients)
void Update () {
double currentTime = Network.time;
double interpolationTime = currentTime - interpolationBackTime;
// We have a window of interpolationBackTime where we basically play
// By having interpolationBackTime the average ping, you will usually use interpolation.
// And only if no more data arrives we will use extrapolation
// Use interpolation
// Check if latest state exceeds interpolation time, if this is the case then
// it is too old and extrapolation should be used
if (m_BufferedState[0].timestamp > interpolationTime)
{
for (int i=0;i<m_TimestampCount;i++)
{
// Find the state which matches the interpolation time (time+0.1) or use last state
if (m_BufferedState[i].timestamp <= interpolationTime || i == m_TimestampCount-1)
{
// The state one slot newer (<100ms) than the best playback state
State rhs = m_BufferedState[Mathf.Max(i-1, 0)];
// The best playback state (closest to 100 ms old (default time))
State lhs = m_BufferedState[i];
// Use the time between the two slots to determine if interpolation is necessary
double length = rhs.timestamp - lhs.timestamp;
float t = 0.0F;
// As the time difference gets closer to 100 ms t gets closer to 1 in
// which case rhs is only used
if (length > 0.0001)
t = (float)((interpolationTime - lhs.timestamp) / length);
// if t=0 => lhs is used directly
transform.localPosition = Vector3.Lerp(lhs.pos, rhs.pos, t);
transform.localRotation = Quaternion.Slerp(lhs.rot, rhs.rot, t);
return;
}
}
}
// Use extrapolation. Here we do something really simple and just repeat the last
// received state. You can do clever stuff with predicting what should happen.
else
{
State latest = m_BufferedState[0];
transform.localPosition = latest.pos;
transform.localRotation = latest.rot;
}
}
}
Hi ExTheSea, I don't know if this will help you but I occurred this kind of flickering (I mean about flickering when move in your example - the jumping flickering when shoot it's a different thing related with sync of jump animation) exactly when I used interpolation and extrapolation scripts available on net in conjunction with sync via NetworkViews. Probably it's related with corrections which your NetworkInterpolatedTransfom script is trying to do. So that after a lot of headaches with sync the players movement, I decided to use not anymore the sync via NetworkView, switching to RPCs to send the positions&rotations to the server, and then, from the server to clients also via RPCs. $$anonymous$$eeping NetworkView sync only for animations and lag compensation.
Thank you for your comment i will look into this and maybe use it for my project if it works out: I'm guessing you have a script that does something like this:
@RPC
function syncPosition(... syncPos : Vector3, syncRot : Vector3){
...
player.transform.position = syncPos;
player.transform.rotation = syncRot;
...
}
...and you call the syncPosition-RPC in the Update function or is it something more complex? If so do you know any documentation which contains information about this technique?
Btw. if someone knows another solution maybe without going away from NetworkViews don't hesitate to post :)
Yes, that's the point I think, as in your RPC prototype. Unfortunately the final scripts and inter-scripts communication finally working for me are pretty complex and difficult to show in few lines of code. As a very good point of start I suggest: http://www.playblack.net/zee-code/ This tutorial helped me a lot. $$anonymous$$eywords there: client movement, server movement (at first instance, ignore lag things)
Note I am not an expert. I was very frustrated to rewrite all movement scripts many-many times to keep all together (movement, animations) working acceptable in multiplayer mode and probably a better solution exist, even including NetworkViews for all the things, but I didn't found it. I think you must be prepared to rewrite all completely for few times, as I was prior to have a multiplayer sync on good enough way. Networking it's a hell place.
Sorry, I didn't read last your three comments before to post, so that I answered to your @RPC example - more closed to my solution.
I tested your Web Demo now and looks better. It's still flickering a bit (it's not about distance and position) but anyway it's better. But if you play with interpolationBackTime with arbitrary values I am not sure it's a good idea. Better to calculate the real delay (ping) and use the resulting value in calculate backtime. The reason you tested and implemented interpolation it's the lag?