[quote name='fholm' timestamp='1314000735' post='4852174']
Vector3 lerpFrom;
Vector3 lerpTo;
float lerpTime ;
void physicsStep() {
lerpTime = currentTimeSinceGameStarted;
lerpFrom = currentPosition;
lerpTo = currentPosition + currentCalculatedInputVector;
}
void update() {
currentPosition = Vector3.Lerp(lerpFrom, lerpTo, currentTimeSinceGameStarted - lerpTime / 0.015f);
}
But no luck with this approach either. And again, for emphasis: It's not insanely jerky, but it's not as smooth as when doing a single player game and doing the movement in the update function with just "currentPosition += movementVector * frameDelta * 50.0f;*
My first thought here is that floating point imprecision could be causing problems. Given the standard lerp implementation of "a' = a + (b-a) * t" and the way you are calculating t, there are a couple places you could be hitting problems with precision. I don't think this is the most likely case but you might want to log out the from/to and the time percentage and see what the values are. If you see numbers like 1000.0001f for a position and a number like 0.0001f for the percentage then you are likely hitting problems in this area. The fix, if that is a problem, is to expand out the entire equation and rearrange things to not perform the division until the last possible point. (Division is usually the worst culprit of floating point error.)
Another variation along the same lines is that the timer code is not accurate enough and you are getting inconsistent deltas. Variations of this include having your time sampling done in the wrong locations such that they are not compensating for varying loop times. If the call to physics is part of the main loop, each time it hits it could be throwing off the delta time considerably such that your time stream is 2ms, 2ms, 2ms, 5ms, 2ms, 2ms, 2ms, 5ms, etc. Each time you hit 5ms your interpolation could/would "jump" considerably.
Finally, why are you lerping at all? My thought on this is to go back to the standard "a' = a + v * delta" and simply recalculate v to point at your target point as it changes from physics/network update. There are some downfalls to this but in general the upside is that your game loop code is written without anything unusual, you get interpolation/extrapolation for free (on a linear path at least) and to perform smoothing/correction you simply modify the v vector smoothly instead of fiddling with absolute start/end points. Fiddling with the v vector to do smoothing and compensation is not the most intuitive item in the world but it is generally easier than doing the lerps all over the place since you can localize the code to one place (generally after physics/network but before the client presentation code).
Mostly the trick to using the velocity item is if the velocity is to be open ended or targeted. What I mean is that if you don't get an updated location and you go past the target point, do you keep extrapolating down the path or go ahead and stop? Sometimes "stop" is the correct answer, i.e. things on fixed paths, mostly not though. The way I did this last time was using a spring system, I let the motion continue past the target but started slowing down until an update arrives. With very bad packet loss and/or variable latencies, this acted as a smoothing system where the objects were not rock solid continual speeds and such but they tended to adjust automatically to the bad network conditions without a lot of code involved. Under good network conditions though, the slight rubber band effect is imperceptible. Keep in mind that this is just for the client presentation, proper latency hiding and all that are done at higher levels, this just helps out and maintains the code in a manner which is not so different than single player code.
[/quote]
Hey, and thanks again for an excellent answer, I owe you a lot!
I've been doing some digging and what you've described here, is what's happening I think:
[quote=AllEightUp]If the call to physics is part of the main loop, each time it hits it could be throwing off the delta time considerably such that your time stream is 2ms, 2ms, 2ms, 5ms, 2ms, 2ms, 2ms, 5ms, etc. Each time you hit 5ms your interpolation could/would "jump" considerably.[/quote]
It's not exactly the same, but basically the
t i use for input to my lerp in the update function never reaches 1.0, so when I go to the physics step there is some movement that still hasn't happened on screen since it only got to 0.8 or 0.75, etc. and then the new physics step will happen and it will jump the position forward and start lerping towards the next one, etc.
I've also learned that using Unity (which is what I am), you shouldn't read input in the physics step (FixedUpdate in unity) as the input state is only refreshed once every frame, which could also be part of my problem. And that using Unity you really should be reading input inside of your Update function, so I did work on a solution that did the input reading and quantification to 15ms steps inside my Update function, and it seems to be working properly.
Basically what I did with the Update based version (instead of FixedUpdate/physics step) was that quantify the commands to 15ms by using delta time and counting upwards in a variable to 15ms and using that to calculate movement and creating commands that need to go to the server, this is how it looks without the server parts:
byte pstate;
float ptime;
Vector3 pvector;
Vector3 cpos;
void MoveCmd(float delta) {
var state = GetKeyState();
// Most uncommon path
if(pstate != state) {
cpos += pvector;
ptime = 0;
pvector = Vector3.zero;
// Most common path
} else if(ptime+delta >= 0.015f) {
delta -= (0.015f-ptime);
cpos += KeyStateToVector(state);
pvector = Vector3.zero;
ptime = 0;
}
while (delta >= 0.015f) {
cpos += KeyStateToVector(state);
delta -= 0.015f;
}
ptime += delta;
pstate = state;
pvector = KeyStateToVector(state) * (ptime / 0.015f);
transform.position = cpos + pvector;
}
It does give me silky smooth movement and seems to be working on both the client and server properly (this is just the client part), i'm just not sure "it's right" (the correct way to do it)? But I saw now other way, especially since unity doesn't update the Input between physics step (only once per frame).
Also one questions, about: [color="#1C2837"]
a' = a + v * delta
[color="#1C2837"]
[color="#1C2837"]How would an implementation of this look, I'm assuming something like:
- [color="#1c2837"]a = current position
- [color="#1c2837"]a' = new position
- [color="#1c2837"]v = vector from a to valid position
- [color="#1c2837"]delta = frame delta
[color="#1c2837"]so in the physics step I would set something like:
[color="#1c2837"]
p = serverposition + allUnverifiedCommandsReapplied
v = p - a // from a to p
[color="#1c2837"]and then in the update/frame step I would do something like this:
[color="#1c2837"]
a' = a + (v * delta)
a = 'a
[color="#1c2837"]but wouldn't this keep me moving "over" my
p ? maybe I'm missunderstanding.
[color="#1c2837"]Again, thanks for all your answers and the time you've taken out of your day to help me!