- Home /
CharacterController.Move precision
I give CharacterController.Move() the exact some input, however the result positions differ from time to time. The difference is something like 0.0000010, but in the long term, it grows huge.
Any ideas, where can I find the roots of this problem?
Answer by Bunny83 · Aug 13, 2012 at 04:10 PM
Sure, here ;)
Well, thank you for pointing out the issues about float precision, but I'm already aware of that. I've managed to make the input every time the same using rounding and casting, however what I figured out, is that the only I thing I can not change and Unity handles it incorrectly, is the position. As I experienced, positions are only stored in x.xx format, so the basic problem is, that after the third point, the numbers are lost.
So the question is basically the following: how can I manage to get the CC to the same position after the same cc.$$anonymous$$ove() command using the same input? What should I cast, round, etc... I can not believe, that there isn't a solution to this kind of problem.
Why do you need such precise movement?
The only way to reach the level of precision it sounds like you're asking for is to cast your floats to integers and work from there.
I'm working on a multiplayer game, where there are two players, and their positions sets the limits where the other can move. So if I'm out of sync for like 0.0000001 game unity, then in the long run they will be totally messed. Syncing their positions is not an option, so I'm catching the whole input and reproducing the whole movement on each machine, and not getting to the same position is not so good.
I was thinking about integers as well, but I must convert them to floats to use the cc.$$anonymous$$ove function (I need to detect collision) so I can not avoid working with float as long as $$anonymous$$ove only accept floats as an input. Until this point, everything is under control and works as expected.
Can you post the code you're using locally and the one you use remote? to move your character? How do you send the input?
The position IS stored as 3 normal float values. That means the bigger the number gets the smaller the precision gets behind the floating point.
If you do the same on two machines it "should" produce the same result if the conditions are 100% the same. There are cases where floating point units from different brands had a different behaviour in certain cases, but usually if it follows the "normal single-floats" (IEEE 754) standard it should be exactly the same. Are you sure that you don't have a time difference or framerate dependencies?
I run every movement calculation in FixedUpdate. What I do right now is, fill up an array with the input from FixedUpdate as well (-1,0,1, no interpolation between them), and send the content of the array periodically in a single string via a local call (for my player locally) and via RPC (for my player on the network) in the same time. I use the exact same script to work with the input transmitted. I break down the string, and get a single input per fixedupdate frame. I do the calculations then do a single .$$anonymous$$ove() (only one per fixed frame). After this I move on to the next input.
The array submitted is exactly the same, I checked it several times, if I sum up the input and the float values used by the .$$anonymous$$ove() method periodically is also the exact same. So the script goes wrong after making the actual movement, and needed to calculate where we are.
Right now I've rounded down every float to 3 point precision to match the vector. This way, I'm getting much closer values, but still not identical.
Here is a bit of code to demonstrate what I am talking about:
newPos.x = input runSpeed 0.02f;
lastIn = (float)newPos.x;
controller.$$anonymous$$ove(new Vector3(lastIn, newPos.y, 0));
last$$anonymous$$ove = (float)(transform.position.x - lastX);
if(lastIn != last$$anonymous$$ove)
{
Debug.Log("Input: " + lastIn + ", $$anonymous$$oved: " + last$$anonymous$$ove);
}
lastX = transform.position.x;
And the output is:
Input: 0.06, $$anonymous$$oved: 0.06000018
Input: 0.06, $$anonymous$$oved: 0.05999994
Input: 0.06, $$anonymous$$oved: 0.06000018
Input: 0.06, $$anonymous$$oved: 0.05999994
Input: 0.06, $$anonymous$$oved: 0.06000018
Input: 0.06, $$anonymous$$oved: 0.05999994
Input: 0.06, $$anonymous$$oved: 0.05999994
Input: 0.06, $$anonymous$$oved: 0.06000018
Input: 0.06, $$anonymous$$oved: 0.05999994
Input: 0.06, $$anonymous$$oved: 0.05999994
Input: 0.06, $$anonymous$$oved: 0.06000042
Input: 0.06, $$anonymous$$oved: 0.05999994
Input: 0.06, $$anonymous$$oved: 0.06000042
However, if the controllers position is between 0 and 1 on the x axis, the output is almost equal.
Your answer
Follow this Question
Related Questions
Precision problem when moving Rect values 2 Answers
maximum distance from origin (float precision) 1 Answer
Losing float precision when adding to Vector3 1 Answer
Convert double to float for Vector3 1 Answer
CharacterController Gravity 2 Answers