Hey everyone. Our game heavily relies on a single physics object that bounces around (much like a grenade). I am in the process of converting the game over from using UT networking to SFS2.0 networking. With a direct connection between the player and server, there wasn't much latency to be concerned about, but now in converting over to SFS2.0, there definitely is. And as I am also improving my networking skills step-by-step, interpolation and extrapolation seem to be the next thing to implement in our game. Is there some way to smooth the interpolation and extrapolation? Its a bit choppy right now and I wanted to tighten it up. I know I have to use the previous positions of my object to better interpolate / extrapolate the object, but how do I do that factoring in the acceleration of gravity? My best guess right now is I'm going to have to do something involving calculus (which is something I'm not very good at). I *think* I have to integrate some formula across my known points and use that to predict the curve... Any ideas?
I jumped into the google and wikipedia, what they had was a bit too complicated for my understanding. Humpf!
got the same problem,in sfs2x fps demo the movement is not smooth enough(even using Extrapolation,there is always a jitter in last position),hope someone give some hints!!
Weren't there some Valve networking tutorials somewhere (I forget where these were mentioned)? I was wondering if there might have been siome info on extrapolation in those.
After some digging, I found this extrapolation algorithm (called Neville's Algorithm) plus some code to go along with it (thank you for Math majors ;-) ) I'm going to PHP it, then see how it works in Unity. Code (csharp): www.cs.uaf.edu/~bueler/nevM.htm
Appels: Hmm-- so maybe my problem is not extrapolation, but rather that I should delay the client game 100ms and work on better interpolation? (On a side not, I believe Neville's Algorithm above works for interpolation as well).
Interesting. Well, I'm still working on converting Neville's Algorithm to UnityScript, but I will likely approach the situation as you mentioned. I'd like to see if Neville's Algorithm is better than just Lerping between two points.
So I finally got more information on Neville's Algorithm for Interpolation Extrapolation. After finding the right article, I was able to pull this together (per the article, it works-- as far as other data samples, I don't know-- this is hot off the press!) This is coded, really, really, really bad and really needs to be worked out a bit. I'm not sure it will compile on iPhone devices, but it is a starting point. The data put in there is the data for sines . The original article I pulled the information from is here: Code (csharp): http://siber.cankaya.edu.tr/ozdogan/NumericalComputations/Fall2004/ceng375/node56.html Code (csharp): function Awake () { var vectors : Vector2 [] = (Array(Vector2(10.1,.17537),Vector2(22.2,.37784),Vector2(32.0,.52992),Vector2(41.6,.66393),Vector2(50.5,.63608))).ToBuiltin(Vector2); Debug.Log(ArrayToString(vectors)); vectors = SortByCloseness(27.5,vectors); Debug.Log(ArrayToString(vectors)); Debug.Log("-----------"); Debug.Log(NevillesAlgorithm(27.5,vectors)); } function NevillesAlgorithm (newX : float, vectors : Vector2[]) : float { //WICKED COMPLICATED (god damn mathmaticians can't make this easier, can you!) //P(i,j) = (x - x(i)) * P(i+1, j-1) + x(x+j - x) * P(i, j-1) / x(i+j) - x(i) return P(0,vectors.length-1,newX,vectors); } function P (i : int, j : int, x : float, v : Vector2[]) : float { if (j == 0) { return v[i].y; } var ret : float = 0; // Debug.Log(i + " " + j); // Debug.Log("P("+i+","+j+") = (("+x+"-"+v[i].x+") * "+P(i+1, j-1, x,v)+" + ("+v[i+j].x+" - "+x+") * "+P(i, j-1, x, v)+") / ("+v[i+j].x+"-"+v[i].x + ") = " + ret); ret = ((x - v[i].x) * P(i+1, j-1, x,v) + (v[i+j].x - x) * P(i, j-1, x, v)) / (v[i+j].x-v[i].x); Debug.Log("P("+i+","+j+") = (("+x+"-"+v[i].x+") * "+P(i+1, j-1, x,v)+" + ("+v[i+j].x+" - "+x+") * "+P(i, j-1, x, v)+") / ("+v[i+j].x+"-"+v[i].x + ") = " + ret); return ret; } function SortByCloseness (xTest : float, inArray : Vector2 []) : Vector2 [] { for (x = 0; x < inArray.length; x++) { for (var y : int = 0; y < inArray.length; y++) { if (Mathf.Abs(xTest - inArray[x].x) > Mathf.Abs(xTest - inArray[y].x) x < y) { var temp2 : Vector2; temp2 = inArray[x]; inArray[x] = inArray[y]; inArray[y] = temp2; } } } return inArray; } function ArrayToString (arr : Vector2[]) : String { var temp : String; for (var i : int = 0; i < arr.length; i++) { temp += "("+arr[i].x.ToString()+","+arr[i].y.ToString()+") "; } return temp; } function ArrayToString (arr : float[]) : String { var temp : String; for (var i : int = 0; i < arr.length; i++) { temp += arr[i].ToString() + " "; } return temp; } Tomorrow, I'm going to work on implementing the above algorithm, as well as setting the delay back 100 ms. Liverol, you are welcome to try the the code I posted above-- make sure to let me know how it works
the code works fine,but don't know how to implement this into my network code,waitting for your test and hints!! LoL
Ok-- well, briefly, what you need to do is build a vector 2 populated with time and the X Y Z values. example: Code (csharp): //we know where the item is at 10.5 seconds... var vec : Vector3 = Vector3(2,3,4); var time : float = 10.5; //we know where the item is at 10.7 seconds... var vec2 : Vector3 = Vector3(1,2,3); var time2 : float = 10.7; //lets build some 2D history vectors of X,Y,Z vectors with time //x history var xVec : Vector2 [] = [Vector2(vec.x, time), Vector2(vec2.x,time2)]; //y history var yVec : Vector2 [] = [Vector2(vec.y, time), Vector2(vec2.y,time2)]; //z history var zVec : Vector2 [] = [Vector2(vec.z, time), Vector2(vec2.z,time2)]; //lets predict where the item will be .2 seconds from now var newX : float = NevillesAlgorithm(10.9,xVec); var newY : float = NevillesAlgorithm(10.9,yVec); var newZ : float = NevillesAlgorithm(10.9,zVec); //predicted position at 10.9 seconds var predictedPosition : Vector3 = Vector3(newX, newY, newZ);
Hey-- I got this working. Try this code. It looks like it is a bit better at Interpolation than just Lerping between known points. The Spheres are Known Positions (data packets that finally got sent to Client) and the Cubes are predicted positions. Attach the script to a camera (in an empty scene) and press run. You should be able to figure it out from there. Code (csharp): function Start () { // var tvectors : Vector4 [] = (Array(Vector4(.17537,0,0,10.1),Vector4(.37884,0,0,22.2),Vector4(.52992,0,0,32.0),Vector4(.66393,0,0,41.6),Vector4(.63606,0,0,50.5))).ToBuiltin(Vector4); // Debug.Log(PredictPositionAtTime(27.5,tvectors)); StartCoroutine(Go()); } function Go () { var vectors : Vector4 [] = Array(Vector4(0,10,2,0),Vector4(.5,5,3,.05),Vector4(1,0,4,.1),Vector4(1.5,2.5,5,.15),Vector4(2,5,6,.2),Vector4(2.5,2.5,7,.25),Vector4(3,0,8,.3),Vector4(3.5,1.25,9,.35),Vector4(4,2.5,10,.4)).ToBuiltin(Vector4); for (var time : float = -.81; time < .8; time += .02) { var pos : Vector3 = PredictPositionAtTime(time,vectors); var cube : GameObject = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.transform.position = pos; Debug.Log("At t=" + time + ", Pos = " + pos); yield WaitForSeconds(.25); } for (var x : int = 0; x < vectors.length; x++) { var temp : Vector3 = Vector3(vectors[x].x,vectors[x].y,vectors[x].z); var sphere : GameObject = GameObject.CreatePrimitive(PrimitiveType.Sphere); sphere.transform.position = temp; } } function PredictPositionAtTime (time : float, vectors : Vector4 []) : Vector3 { var xVec : Array = Array(); var yVec : Array = Array(); var zVec : Array = Array(); // Debug.Log(ArrayToString(vectors)); vectors = SortByCloseness(time,vectors); // Debug.Log(ArrayToString(vectors)); for (var x : int = 0; x < vectors.length; x++) { xVec.Add(Vector2(vectors[x].w,vectors[x].x)); yVec.Add(Vector2(vectors[x].w,vectors[x].y)); zVec.Add(Vector2(vectors[x].w,vectors[x].z)); } // Debug.Log(ArrayToString(xVec.ToBuiltin(Vector2))); // Debug.Log(ArrayToString(yVec.ToBuiltin(Vector2))); // Debug.Log(ArrayToString(zVec.ToBuiltin(Vector2))); var newPos : Vector3; newPos.x = NevillesAlgorithm(time, xVec.ToBuiltin(Vector2)); newPos.y = NevillesAlgorithm(time, yVec.ToBuiltin(Vector2)); newPos.z = NevillesAlgorithm(time, zVec.ToBuiltin(Vector2)); return newPos; } function NevillesAlgorithm (newX : float, vectors : Vector2[]) : float { //WICKED COMPLICATED (god damn mathmaticians can't make this easier, can you!) //P(i,j) = (x - x(i)) * P(i+1, j-1) + x(x+j - x) * P(i, j-1) / x(i+j) - x(i) return P(0,vectors.length-1,newX,vectors); } function P (i : int, j : int, x : float, v : Vector2[]) : float { if (j == 0) { return v[i].y; } var ret : float = 0; // Debug.Log(i + " " + j); // Debug.Log("P("+i+","+j+") = (("+x+"-"+v[i].x+") * "+P(i+1, j-1, x,v)+" + ("+v[i+j].x+" - "+x+") * "+P(i, j-1, x, v)+") / ("+v[i+j].x+"-"+v[i].x + ") = " + ret); ret = ((x - v[i].x) * P(i+1, j-1, x,v) + (v[i+j].x - x) * P(i, j-1, x, v)) / (v[i+j].x-v[i].x); // Debug.Log("P("+i+","+j+") = (("+x+"-"+v[i].x+") * "+P(i+1, j-1, x,v)+" + ("+v[i+j].x+" - "+x+") * "+P(i, j-1, x, v)+") / ("+v[i+j].x+"-"+v[i].x + ") = " + ret); return ret; } function SortByCloseness (wTest : float, inArray : Vector4 []) : Vector4 [] { for (x = 0; x < inArray.length; x++) { for (var y : int = 0; y < inArray.length; y++) { if (Mathf.Abs(wTest - inArray[x].w) > Mathf.Abs(wTest - inArray[y].w) x < y) { var temp2 : Vector4; temp2 = inArray[x]; inArray[x] = inArray[y]; inArray[y] = temp2; } } } return inArray; } function SortByCloseness (xTest : float, inArray : Vector2 []) : Vector2 [] { for (x = 0; x < inArray.length; x++) { for (var y : int = 0; y < inArray.length; y++) { if (Mathf.Abs(xTest - inArray[x].x) > Mathf.Abs(xTest - inArray[y].x) x < y) { var temp2 : Vector2; temp2 = inArray[x]; inArray[x] = inArray[y]; inArray[y] = temp2; } } } return inArray; } function ArrayToString (arr : Vector4[]) : String { var temp : String; for (var i : int = 0; i < arr.length; i++) { temp += "("+arr[i].x.ToString()+","+arr[i].y.ToString()+","+arr[i].z.ToString()+","+arr[i].w.ToString()+") "; } return temp; } function ArrayToString (arr : Vector2[]) : String { var temp : String; for (var i : int = 0; i < arr.length; i++) { temp += "("+arr[i].x.ToString()+","+arr[i].y.ToString()+") "; } return temp; } function ArrayToString (arr : float[]) : String { var temp : String; for (var i : int = 0; i < arr.length; i++) { temp += arr[i].ToString() + " "; } return temp; }
really thanks for the details,still confused to use this in sfs2 fps demo,would you please check the fps demo scripts and convert to above algorithm?this should be useful for you too! I just attactched the 2 main scripts if you don't download the sfs2x fps demo,this is the Interpolation core scripts! Appreciate!