Should positions be defined as ints or floats?

Started by
21 comments, last by Sean_Seanston 12 years, 8 months ago
Up to now, I've just decided to use floats to store the positions of objects in my basic 2D games figuring I may as well and it might help keep things smooth at some point or if I ever need to add a gradation of less than 1 to a position then at least I'll be able to without changing things from int to float.

Now I've come into a problem that makes me wonder again whether ints or floats are a better idea.

I'm trying to implement a collision handling algorithm that takes 2 colliding objects' old positions and their velocities, then moves them back toward their old positions gradually until no collision occurs.
Only after writing the code and running it a few times, outputting some debugging info, did I realize that the floats I was using for position were complicating things. I was trying to decrement (or increment) the velocities but since they and the positions were floats, subtracting/adding 1 didn't seem to make as much sense as it would've with ints and my code to get the decrementing/incrementing to stop at 0 wasn't working because it skipped over being exactly 0 if the values weren't equal to exact integers.

I could clean that up of course and get around it, but I'm back wondering something I've been wondering about for some time but was never forced to think about very much: Should object positions (specifically in 2D games moreso) be floats or are integers generally just as good and easier/more logical to work with? What are your experiences with this? Should I go back and change the floats to ints or are there significant advantages to using floats?
Advertisement
Sounds like floats aren't the problem so much as your methods for comparing them.

Since floating point numbers are inherently imprecise, you need to use an epsilon value to check if they are (almost) equal. So for instance:

// Bad
if(some_number == 2.0f) { foo(); }

// Good
if(abs(some_number - 2.0f) < 0.0001f) { foo(); }


Of course you should use a constant someplace instead of hard-coding your 0.0001f everywhere. It might also make sense to implement this as a function "roughly_equal" or similar.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Floats aren't 100% precise but this is a problem based on calculations being base 2 and can cause some collision errors.

Int would be simplest to work with, it's easy to iterate and most positions in games can be scaled up or down to an int. Unless you're doing calculations that require you to use fractions or division (really the same thing)...I don't suggest using float.
If it is 2d, and pixel based, you may as well go with integers. Of course, if it were 3d, you would likely be stuck with floats, unless it were grid-based.


For a 2D game I would recommend either using fixed-point (e.g. 24.8 format), or just sticking with floating point.

Using integer positioning results in very jagged movement. Once you've properly used Fixed-point, you wont be able to stand how jumpy using straight out integer coordinates is.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

Sounds like floats aren't the problem so much as your methods for comparing them.


How are floats for position in 2D games in general though?

I suppose I'll stick with them either way at this stage...

Since floating point numbers are inherently imprecise, you need to use an epsilon value to check if they are (almost) equal. So for instance:

// Bad
if(some_number == 2.0f) { foo(); }

// Good
if(abs(some_number - 2.0f) < 0.0001f) { foo(); }


Hmmm... good idea. I'll keep that in mind.


If it is 2d, and pixel based, you may as well go with integers. Of course, if it were 3d, you would likely be stuck with floats, unless it were grid-based.


Well being that I've gone with floats so far... I guess I'll keep them. Might be good practice for future 3D stuff too to an extent.


Using integer positioning results in very jagged movement. Once you've properly used Fixed-point, you wont be able to stand how jumpy using straight out integer coordinates is.


Yeah... I thought about jaggyness but my current system uses interpolation to smooth out movement, so objects are drawn at float coordinates in between their last 2 positions or thereabouts so it looks nice and smooth. Not sure then what way I have it exactly if switching to ints would cause a problem... but I'll just stick with them now.

Question:
- When I'm slowly stepping the objects back to check for the first point where they don't intersect, what increment should I use? Is 1.0 too large? Another thing is that maybe no matter what step I use, I'll end up where the objects aren't exactly rubbing against each other like would be ideal, since we're not checking every single possible position like would be easy with integers.

So how should I really approach this kind of algorithm with floating points anyway? Accept the small gaps between objects that are bound to occur (realistically probably wouldn't make a noticeable difference I assume)? Or is there some better way?
Part of why I thought stepping would be better was that I wouldn't have to deal with if statements determining what side things were approaching from in order to determine whether they should be set to hug the edge of the other object, but with floats it seems doing it exactly would be complicated but I dunno.

Thoughts?

EDIT: Does anyone have any links to anywhere discussing this kind of algorithm? I've started to encounter a lot of complications I can't figure out how to solve... such as how to stop velocity being reduced when it shouldn't be like when object 1 is going straight up, but object 2 runs into the side of it, object 1's y velocity shouldn't be touched..
Okay, here's what I mean... I've drawn a diagram that I hope is easy to follow, illustrating 2 different cases of movement and a resulting collision, where the objects' positions + velocity result in the same positions in each case but where different behaviour would be expected:
collisiondiagram.png

In the diagram, the green shapes represent objects in their initial positions, red shapes represent their initial positions + velocities, and red arrows represent direction of movement to make it slightly clearer.
In Case 1, Object 1 slams into the side of Object 2 as it travels upwards. The desired effect would be for Object 2 to be unaffected and Object 1 to be repositioned as close to Object 2 as possible along the X axis without overlapping with it.
Case 2 results in the same end positions if the velocities were to be added to their previous positions, but this time, Object 2 is coming up from beneath Object 1 and colliding. Here you'd want Object 1 to be unaffected and Object 2 to be repositioned next to Object 1.

How might you factor all of this into such an algorithm? Clearly, the initial positions must be taken into account but I don't trust myself to come up with something that works without a maze of if statements or switches and elaborate boolean statements.Then of course it has to work on all other cases such as diagonal movement and with only 1 and both moving etc. etc.
Well it seems everyone explained pretty in depth the particularities of floating point regarding logic, but I see no mention to render, so I'll get on that particular topic.

Yes, traditionally position is declared and stored as floating point, and yes performing an equality check on a float is virtually pointless.
Having said that, in a 2D world, you should also have a uniform method to turn float positions into int for rendering purposes, see, textures are rendered by discrete portions we call pixels, since they are discrete, they cannot have a meaningful decimal position. The graphics card will try to round up your floats into ints, however this often generates graphic artifacts in 2D, specially for tile maps, rounded positions may not preserve relative distances and therefore leave gaps between tiles or overlap tiles, specially when scrolling the camera with a floating point controlled position.


Making the conversion yourself can prevent this well enough

Game making is godlike

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272


Hmmm... I see what you mean NEXUSKill... makes sense... I'll have to keep that in mind. Don't THINK it's been causing me problems yet though. I'll have to keep an eye out in future.

Anyone have any ideas re: my diagram problem?

I've heard of this collision handling method before so there must be some fairly standard ways of doing it.
[color="#1C2837"] The graphics card will try to round up your floats into ints, however this often generates graphic artifacts in 2D[/quote]
[color="#1C2837"] [color="#1C2837"]This is hardly true at all. All operations done on the a graphics card are floating point from fragment transformation to rasterization. Floating point values are valuable to the graphics card. Anti-aliasing requires sub-pixel measurements. When it comes time to writing the color to video memory a simple integer truncation is performed, no rounding. And to get technical, you can have a discrete set of decimals. Think of a set containing values in increments of 0.5..

This topic is closed to new replies.

Advertisement