X, Z axis on transform.position glitchy

This took a while to track down, but it is easy to reproduce, the Z axis numbers are WAY off when reported back by the transform.position of an object, I first started seeing this happen with my multiplayer games, but didn’t think too much of it, was blaming it on packet inconsistancies, then I created a new project to simply test the position of the player in a step by step movement system (has documented into other threads), this is so easy to test and program I am very supprised that others haven’t ran across this problem in Unity 2.6.1 on Windows.

Taking the code that I was helped with in another thread for simple movement, attaching it to the camera on a blank / empty project, and simply hit the play, it is that simple to setup the project and test, here was the code:

  void Update()
  {
    if (Input.GetKeyDown("up"))
    {
      transform.position = transform.position + transform.forward;
      Debug.Log("X:" + transform.position.x.ToString() + " Y:" + transform.position.y.ToString() + " Z:" + transform.position.z.ToString());
    }
    if (Input.GetKeyDown("down"))
      transform.forward = -transform.forward;

    if (Input.GetKeyDown("left"))
      transform.forward = Quaternion.Euler(0, -90, 0) * transform.forward;

    if (Input.GetKeyDown("right"))
      transform.forward = Quaternion.Euler(0, 90, 0) * transform.forward;

  }

Thats all the code you need in your entire scene to test and see this problem. When you click on the up arrow to move forward, you would expect the following results:

X:0 Y:1 Z:1

Now, click on the right arrow and hit the up arrow, you would expect to see:

X:1 Y:1 Z:1
However, my results on this very first movement was:
X:1 Y:1 Z:0.9999999

Not horrible yet, just off by a very slight float amount, now hit the left arrow and then the up arrow again, you would expect to get:
X:1 Y:1 Z:2

Now keep repeating this process a few more times:
Eventually if you keep playing with it, Z will jump by 4 or 5 places, but your position will be different than reported by X, Z coordinates, if you hit the Up arrow, Right Arrow, Up arrow and Right arrow consitantly, you should only be moving X, Z by +/- 1 spot because you are moving in a circle, but it will jump by 4 in this small demo.

http://screencast.com/t/NDA4NWM4Yj

Now, in this video, all I did was move in a perfect square, 4 spots, and both X and Z eventually jumped, I have successfully tested this with different versions of code to move the camera 1.0f at a time. This can also be noticed on larger scale smoother movement systems including the normal pill player code in the unity package, it isn’t very obvious because it is correct in the next game frame or two, however, this glitch has the data sent across the network to other players causing them for 1 game frame or 2 game frames to be way out of position, and unless you have a game with a simple movement or single position movement, you will not notice it, if at all.

I wouldn’t have noticed it as much without the data being corrupted and thinking it was just me and my packets, as you can see I didn’t even have the server running so I didn’t have any other players in the scene, this is a pure data example. So take that code, attach it to a camera, use the up and right arrows ONLY and use them rapidly as in Up, Right, Up, Right, etc and keep yourself in a square movement and watch your numbers. This is causing me hell with my games at the moment, especially my turn based multiplayer dungeon game, players jump to different areas of the dungeon when this happens and then jump back, and that just will not do.

Welcome to computers and floating point single-precision math. This doesn’t have anything to do with Unity in particular. If you want exact integer results, round them off. Also it seems to me the code would be easier to read if you made use of Unity’s built-in functions:

	if (Input.GetKeyDown("up"))
		transform.Translate(Vector3.forward);

	if (Input.GetKeyDown("down"))
		transform.Rotate(Vector3.up*180);
		
	if (Input.GetKeyDown("left"))
		transform.Rotate(Vector3.up*-90);
		
	if (Input.GetKeyDown("right"))
		transform.Rotate(Vector3.up*90);

–Eric

Actually eric, I had that in code at one point, but that gets VERY jumpy and doesn’t work right -at all- over time. Did you happen to watch the video? Like I had stated, I tried quiet a few different ways, and the rotate also causes havoc. It shouldn’t matter “how” i rotate the player, and if you notice a floating point “jump” of x4.0f isn’t the same as .00001 in math at all. It is late but tomorrow I will use that code (which I have already tried way back when I first started, which is documented around the threads somewhere), another block of code that I tried, and yet the one I posted here, all of which do the same thing, they turn the player, and move the player 1.0f forward based on pressing the “up” arrow key.

I guess my point is, 0.000001 off is different than 4.xxx off, which is proven in the video. If I create a video proving a point and that point is missed completely, I am not even sure then how to post the problem if a visual isn’t proof enough.

Edit:
Actually I think I know how the point won’t get missed, More than just making videos proving the problem, I will screen print the problem, post the screen print with red circles around the jump in numbers and have a hug list of proof here instead, the player physically “JUMPS” in coordinates from being a single 1.0fx1.0f.1.0f movement to X4.xxxf,1.0f,X4.xxxf, then a few frames later returns to a proper 1.0fx1.0fx1.0f movement.

See here for a controller script that moves perfectly from one square to another. There is no issue with Unity that’s not caused by floating-point imprecision, which is a universal problem and pretty simple to compensate for (and also why you do not write financial software using floating-point, at all). floating point imprecision - Google Search

–Eric

I am totally fine with small floating point inprecisions, it is when the floating point inprecision turns into a HUGE gap for > 4.Xf in size, but as I stated, this is part of the TRANSFORM.POSITION returning to me where I am in the world, that returned value is WRONG, on the screen I still have only moved visually by 1 spot as an individual, but on the recipient side do to me passing the TRANSFORM.POSITION value that is given back to me by Unity, the associated receiver gets a bad value for a frame or two, again, it is in the video, I will take a look at your linked code and I will create another video later tonight because even without visiting that link, do to the fact I have used 3 different versions of movement code for square movement, and then using the standard assets player prefab, they ALL have the same problem, all of them, the TRANSFORM.POSITION returns invalid values from time to time, completely invalid, and is only invalid for a few frames, then it is back to normal a few frames later for the TRANSFORM.POSITION values.

Attached is 2 data dumps, I made this painfully easier to track and show you what I mean. I created a little CS file that when attached to a player object (like the camera in this instance or pill or whatever) you can dump out how ever many levels of vector3’s to a CVS file, it creates 2 files, one for the fixed update and one for the update, attached is that code and 2 results files.

As I mentioned earlier, this is not that obvious and rarely noticeable on the first person controller, but it still happens, but if you are moving a player by >=1.0f(with float changes), the player data JUMPS, at the most any given X/Z coordinate should change ± 1.0f(give or take) but look at the values.

FYI

has no bearing on this conversation (and another FYI I write financial applications and insurance applications and have for over a decade, so that is sort of insulting)

(edit, fixed the RecordMovement.cs so that the files are saved with extension of csv instead of cvs)

253518–9123–$updatepositions_142.txt (2 KB)
253518–9123–$updatepositions_142.txt (2 KB)
253518–9126–$recordmovement_461.cs (3.82 KB)

If you’re getting those results over the network layer, perhaps it’s an issue with dead reckoning? Just a random thought.

Those results are all local, without the network layer connected. This is all local player data “to be sent”, I checked the data before and after sent when received on the other end and they match, the problem is, the data “to be sent” is corrupted before it is even sent. The player position using transform.position but utilizing current position * delta time, with fractional movement has small seperations in movement for values, but the larger the gap you make the movement, in my example 1.0f shows the problem on a larger scale which is what I have demonstrated in the recorded data and in the video.

Now, if the data was +/- 1.xxxxf on the sender, and the recipient has the jump of +/- 4.xxxxf, then I could see packet corruption, but with the elimination of the network layer by using an empty project with nothing but the moment code and dumping the movement data to file, you can see the results are not pretty.

Edit:
Eric, your code is a smooth scroll/movement code, not one that changes the players position by a factor directly related by a value of 1.0f, your doing a smooth movement between locations, not a solid movement between locations, like 1.0f to 2.0f change of position, your allowing the player (like from your cube game) to smoothly go from 1.0f to 2.0f so you will not really notice this “jump” as much since you are doing micro changes in location, even your movement values are not by 0.01xF, but they are 0.03xf → 0.05xf which is similar to my issue but on a smaller scale and you correct the last position by rounding and setting the position as solid on that final position, so that “jagged” jump at the end is a micro amount so the players would not notice the correction.

As long as your position update happens with a discrete quantum that satisfies ^2 in both the mantissa and exponent you’re golden.

Well, there in sits the problem, if it was a fractional difference was within a given range of +/- .04 (or even .4) it wouldn’t matter, I am talking about a difference of +/- 4 (give or take) when the jump happens in calculations. I shouldn’t have to put in a formula for every movement of the player to determine if they have exceeded the range of +/- 2. The player is actually only moved 1.xxxxxf spot on the screen, but the transform.position is off when it is reported.

So basically I have to take the X and Z, get a pre-determined allowed movement from current location, then determine if the player position is returning to me as > 1.xf or < 1.0f then see which side has changed, if both changes, then send assumed movement coordinates because eventually Unity will give me correct values.

Taken that a player is at 0,0,0 I have to keep building up a table of valid movements, so then the player wants to move to 1,0,0 which is a valid movement, but whent hey move there on the client side, the transform.position tells me that they are now at 4,0,0 but in fact they moved 1, so on the client they are at 1,0,0 but the transform.position tells me that they are at 4,0,0, so I know that the X increased, so I would then have to broadcast to the other players a 1,0,0 position of the player and ignore the current value but only use the value as a reference as to which coordinate changed.

This is basically what I have to do which adds overhead to the program because on every “up” hit on the keyboard, they move in the particular direction they are facing and always by 1, never more, so I will always have to keep a vector table to understand where they are “supposed” to be and just use the transform.position to understand where they “want” to go, not where they actually are in this case.

That is nuts.