Having stopped to think about this some more, the answer is suddenly obvious: there’s nothing wrong with transform.translate, or floating-point maths, or coroutines. The one mistake all along is the belief that starting a coroutine in Start() and then calling yield return new WaitForSeconds
in an infinite loop will cause it to be run exactly once a second, on the second, for the duration of the game. It won’t.
On each iteration, the code in the coroutine itself will take a (very small amount of time to run), then it will wait for a second, and then it will be scheduled to run again on the next frame after the wait. So, if your game runs at 60FPS, say, your coroutine schedule will “slip” by, on average, half of 1/60 of a second each time it yields. The numbers you’re seeing reported in the console are correct, but they’re not at the time you think they were measured.
Try changing the Debug.Log line in your console to this instead:
print ("After " + Time.timeSinceLevelLoad + " seconds, A is at:" + A.position.x +"," + "B is at:" + B.position.x + ", Difference is: " + X);
Which gives me:
Now, there’s still a slight issue - each object’s position is apparently reported 0.02 seconds ahead of where you’d expect it to be for the stated time. This is the length of time of the default physics timestep, which I can’t help but feel isn’t coincidence, but don’t know enough about the exact inner workings of Unity to explain why. However, I am satisified that the distance at each reported step is equal to the value of the slower object, exactly as expected, and you can clearly see the “slipping” of the coroutine.
If you want a more reliable reporting of distance every second, you might want to try InvokeRepeating() instead, which will set up a schedule to call the function on the frame as close to the start of each second as it can. You’ll still not get the exact integer values you were looking for, but you should be able to avoid the slippage problems of the yield.
i.e.
void Start () {
InvokeRepeating ("DoTimer", 0, 1);
}
void DoTimer () {
float X = A.position.x - B.position.x;
print ("After " + Time.timeSinceLevelLoad + " seconds, A is at:" + A.position.x +"," + "B is at:" + B.position.x + ", Difference is: " + X);
}