I'm torn...
Another possibility is that instead of storing world coordinates as int+float, we can use doubles:
- Both solutions are the same size in memory.
- With doubles, even if they're slower than floats, you can use standard vector math. With int+float you need to write world position manipulation that operates on the int coords and the float vec, then possibly "recanonicalize" (which requires divides and mods, etc).
Say that you want the distance between two points far apart in the game world.
With doubles it's straightforward:
(I don't user operator overloading here)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | struct v2d {
real64 x, y; //a pair of doubles
}
v2d
subtract (v2d p1, v2d p2) {
v2d res = {};
res.x = p2.x - p1.x;
res.y = p2.y - p1.y;
return res;
}
double
length(v2d p) {
double res = sqrt(p.x*p.x + p.y*p.y);
return res;
}
double
distance(v2d p1, v2d p2) {
v2d d = subtract(p1, p2);
return length(d);
}
|
With int+float, you need:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | struct v2 {
real32 x, y;
}
struct coord {
uint32 x, y;
}
struct world_pos {
coord c;
v2 p;
}
world_pos
subtract (world_pos p1, world_pos p2) {
world_pos res = {};
res.c.x = p2.c.x - p1.c.x;
res.c.y = p2.c.y - p1.c.y;
res.p.x = p2.p.x - p1.p.x;
res.p.y = p2.p.y - p1.p.y;
//possibly recanonicalize res???
return res;
}
??
length (world_pos p) {
???
}
|
For a subtraction, you're roughly operating on the same number of bits in both cases (128). But if you need to recanonicalize, int+float is gonna be slower.
To compute the length of a world vector, with int/float, you would need to return a scalar int+float to maintain full precision. And the math isn't obvious to me.
With world positions as doubles, when you want to do lots of fast "local" physics, you can convert all your world double positions for objects in the local sub-space into some float vector in a local frame of reference:
| v2
convertToLocalPos( v2d localOrigin, v2d worldPosition) {
v2d localPos = subtract(worldPosition, localOrigin);
v2 res = {};
res.x = (real32) localPos.x;
res.y = (real32) localPos.y;
return res;
}
|
int+float does have the advantage that the precision doesn't depend on world location at all.
Also, the coord part (the ints) can be use to do some sort of broad phase collision detection (you can easily use them as indices into a quadtree).