GradualGames wrote:
Yes of course I considered endianness (and made assumptions since I can't test this right now), but felt it was a reasonable assumption you were talking about making non portable code for the NES.
Sure, the code is not portable. But I still prefer to use C constructs in the way they are intended.
GradualGames wrote:
*edit* TBH, your approach could be described as a hack, too, since you're having to use something other than the cpu's normal operation to imitate fixed point math
There is a difference between a programming trick or compensation for missing features and a hack. My approach is not a hack because it is still valid C. I don't violate the
language features to create a code that does something the language was never intended to do. I just use an alternate version to implement a
program feature. This method will still work with any C compiler since it's totally well-defined and valid C.
A hack is something like the stuff we tried to do with the union:
From the language's point of view, you are only supposed to use one of the properties at a time. The others are in an undefined status.
Now, if you use the union in a way that both properties are valid at the same time, then you do something the language isn't designed to do. This is dangerous behavior because you rely on the fact that the compiler's internal operations work in a specific way. Even if big and little endian is fixed, this doesn't give you the guarantee that a two bytes variable in a four bytes memory is located at the beginning. If the creator of the compiler decides to shift the data internally in the next version, then the program will break as soon as you update the compiler.
There might be some things that, in any other context, would be considered bad writing style. Like using global variables and no function parameters. Or using two separate variables for fixed point math. But these are still valid language constructs that act in a pre-defined way and someone who reads the code can understand it.
Hacks are the things where you rely on the fact that the internal implementation of the compiler does a certain thing in a certain way. You abuse a feature that isn't supported by the language and whose behavior is actually undefined and it just works because you tried it out and adjusted your code, so that it matches the way the compiler implemented it. Someone who reads the code might have a hard time understanding what you're trying to do and it might break in a future version of the compiler.
tepples wrote:
Just use a 16-bit int, let the compiler's support for 16-bit ints do the work, and right shift the coordinate by 8 before displaying the sprite.
This might work if I didn't use a 16 bit integer for the X and Y coordinate to begin with. I need an int to decide whether a certain character is even within the visual area of the screen. So, for jumping and comma values, I need that integer
and a byte variable.
Also, using an int or a long for these operations (letting the lowest byte being the comma value and the second to lowest byte being the actual lowest byte of the integer number) has its own performance problems because it wouldn't be just shifting the value during the output. You also have to shift the value whenever you do a collision check with the environment. For every single character. Even if this character cannot even jump.
I guess there would be too many potential side effects that you have to remember and adjust to in your code if you have a Y coordinate whose value doesn't equal the actual Y position, but where the position is (value >> 8).
Having a separate value for the comma stuff on the other hand makes no fuss: You work with your Y value as always. And that comma value is just used for jumping. You have one place in the entire code where you do a manual
if comma >= 100 then ++Y, comma -= 100 and that's it.