If you’re still worrying about what goes on in the hash function, don’t worry about it.
You don’t have to understand how it works to understand what it does.
It could just as easily be:
uint32_t hash(uint32_t value)
// 127 and 8191 are prime numbers
// (specifically 'mersenne primes')
return ((value + 127) * 8191);
uint32_t hash(uint16_t x, uint16_t y)
const uint32_t x2 = x;
const uint32_t y2 = y;
const uint32_t value = ((x2 << 16) | (y2 << 0));
uint32_t hash(int16_t x, int16_t y)
return hash(static_cast<uint16_t>(x), static_cast<uint16_t>(y));
The important thing is the job that the hash function does:
- It takes a pair of coordinates (x and y) and returns a seemingly random value (i.e. there should be no obvious pattern to the output)
- It provides a valid output for all possible combination of input values (i.e. it’s a ‘surjective’ function)
- It always provides the same output for the same pair of inputs and it has no side effects (i.e. it’s a ‘pure’ function)
Any function that meets those three criteria could be used for the hash,
the only difference would be in the quality of the result.
I’m not sure what you mean by this.
I think you might be getting the meaning of ‘coordinate system’ mangled.
Usually for a 2D game there are only two coordinate systems that need to be taken into account: world coordinates and view/camera/screen coordinates.
(For a 3D game there’s usually two other systems to take into account.)
The typical way to handle a 2D world is to give all the terrain static coordinates (i.e. non-changing coordinates),
and all movable objects/entities dynamic coordinates (i.e. changing coordinates).
Then there’s a ‘camera’ object which represents the screen,
and that object moves around the map.
Then when it’s time to render, the world coordinates are translated to screen coordinates by subtracting the camera’s position.
(Excuse the hand-drawn diagrams, I find hand drawing quicker and easier than digital drawing.)
For example, if the camera object is at (16, 16) (top left coordinate), and an enemy is at (64, 64),
then when they’re translated into camera/view/screen space,
the camera will be at (0, 0) (so the camera’s top left coincides with the screen’s top left),
and the enemy will be at (48, 48) (
(64 - 16) == 48).
They’re literally just a block of memory with values laid end to end.
int array would be 8 bytes.
In memory it would look something like this:
[0x0400] array, low byte
[0x0401] array, high byte
[0x0402] array, low byte
[0x0403] array, high byte
[0x0404] array, low byte
[0x0405] array, high byte
[0x0406] array, low byte
[0x0407] array, high byte
The hex values represent RAM addresses, I made up the address values.
The low byte comes first because AVR is ‘little endian’ (like x86),
which means lower valued bytes are stored first.
Point consists of 2
int16_t, which are two bytes.
In memory a
Point looks something like this:
[0x0500] x, low byte
[0x0501] x, high byte
[0x0502] y, low byte
[0x0503] y, high byte
So an array of two points,
Point points, would look like this in memory:
[0x0600] points.x, low byte
[0x0601] points.x, high byte
[0x0602] points.y, low byte
[0x0603] points.y, high byte
[0x0604] points.x, low byte
[0x0605] points.x, high byte
[0x0606] points.y, low byte
[0x0607] points.y, high byte
That’s literally all there is to it,
the data is just stored in memory contiguously,
and the compiler handles all the maths needed for moving the data around.