I “hate” floating point and often think “why is this still being used? You’d think by this point CPUs would have fixed point math support internally.”
Anyway, so I use integers to implement fixed point numbers.
You can use either int or long depending on your needs.
int has a range of -2,147,483,648 to 2,147,483,647
long has a range of –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
Basically, you can store the values as integers and when dealing with Unity specific stuff (Vector3, etc) that requires floats you do the conversion at that time.
If you need a precision of 2 decimal places you can go with an int and divide by 100 for conversion to a float.
This will give you a range of -21,474,836.48 to 21,474,836.47
If you need a precision of 4 decimal places divide by 10,000 for conversion to a float.
With an int, this will give you a range of -214,748.3648 to 214,748.3647
If you need to represent values less than -214,748 or greater than 214,748 you can use longs.
The long will give you a range of –922,337,203,685,477.5808 to 922,337,203,685,477.5807
I don’t see any issues with speed because internally you just code everything using the integers and you drop to the floats only when necessary (positioning in Unity, etc).
If you are really interested in maximizing raw speed than you can use bit shifting.
For this, instead of dividing by 100 you divide by 128. Being a power of two a simple bit shift can be performed.
I do not use this because I prefer to have a 1 to 1 meaning between the integer and the float.
If your code is scripted directly to a game object and using the Unity data types for everything it may be a bit more hassle to use integer value approach.
I always have 2 code objects for every GameObject.
For example, the player has a PlayerGameObjectScript. This is the main script set right inside the Unity Editor. It contains (“has a”) PlayerBehavior object.
The PlayerBehavior class actually implements all of the logic. It has an Init() method and an Update() method.
Init is called from the PlayerGameObjectScript during Start() (or sometimes Awake()) and Update is called from the PlayerGameObject’s Update method. The PlayerGameObjectScript has a Vector3 Position variable which is loaded each frame with a call to a property in PlayerBehavior. The transform.Position is set to that variable.
Doing this keeps all of the Unity specific stuff separate from the actual game logic stuff. And it makes it much simpler to do stuff like the fixed point math because you have a finite number of very few conversion points perhaps only 1.