jasjisdo / gtge

Automatically exported from code.google.com/p/gtge
2 stars 2 forks source link

Many graphics-based objects in GTGE use double precision #7

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
Many graphics-based objects in the GTGE framework use double precision.  
This is bad, because doubles have many problems for graphics:

1.  Graphics are normally drawn as an array of pixels, using matrix 
notation.  Although some graphics may pretend to let you draw at (double, 
double), usually it just simply casts those doubles to ints, as Sprite's 
render(Graphics2D) method does.  There is no such thing as one half or one 
tenth of a pixel!

2.  Collisions are also using doubles, without a delta.  A delta specifies 
how much precision you don't care about.  But since collisions happen on a 
graphics-context where pixels (whole values) are drawn, doubles don't make 
sense.  Furthermore, without a delta, you may get this:

double firstPosition = 3.0000000001

double secondPosition = 2.999999997

These two would collide in an integer context (they would be equal to 3), 
but since doubles lack precision like that, they end up not registering as 
a collision.  Doubles suffer from precision issues, especially during 
complex calculations (such as the "pixel-perfect" collision calculation).

I recommend anything using doubles that need to be either drawn or 
calculated be switched to ints if it does not make sense to have the 
double values available.  If double values are needed, BigDecimal should 
be used to keep track of precision instead.

Original issue reported on code.google.com by MetroidF...@gmail.com on 6 Apr 2008 at 5:34

GoogleCodeExporter commented 8 years ago
double is used because of sprite velocity is based on time, for example:
elapsedTime = time taken since last update
position += velocity x elapsedTime;
Velocity can be 0.05 for slow speed, and thus need double for slow increment.

Original comment by pau...@yahoo.com on 6 Apr 2008 at 7:01

GoogleCodeExporter commented 8 years ago
I apologize that my last post was unclear.  My wording did not match my 
intention.  
Please allow me to clarify.

I'm not suggesting changing double for velocity.  It *is* needed for that (even 
if 
you can't move 2/3 of a pixel, the next iteration needs to have 1 and 1/3, or 
1, 
pixel movement).  For instance, it should still be allowed to move half a pixel 
per 
x seconds (which translates, in reality, to 1 pixel every 2x seconds).  
Velocity is 
pixels/time, and some velocities do play nice with that respect (such as 0.5, 
and 
0.25, etc).

But sprite positioning needs to be based on integers for true collision 
handling.  
Otherwise you can and will get errors because of double storage.  You also 
cannot 
render a sprite (or even a string of text via GameFont, which DOES use ints) 
with 
doubles...you must use ints.  Which means Sprites keep bigger values than they 
need, 
and must constantly downcast them anyways (the same goes for collision 
handling, as 
again, you cannot occupy a fraction of a pixel, you are either there or you are 
not).

The logic of using doubles for velocity is sound.  You will get minor errors 
over 
time, but they should not be too great (and in fact there may be some point 
where a 
user discovers that they need greater precision, and a delta would then be 
added to 
velocity calculations, or BigDecimal can be used instead).  But for 
"pixel-perfect" 
collisions, double is impossible to accurately describe "pixel-perfect".  
Doubles 
take more space and cause more errors and don't make sense for graphic 
positioning, 
as graphics are really just a big index-based matrix anyways.

So, basically, I propose altering positioning functions such as moveTo(x, y) 
and 
getX(), getOldX(), etc. to ints.  Those dealing with velocity should still take 
doubles for speed, but integers for position values.

Original comment by MetroidF...@gmail.com on 6 Apr 2008 at 8:39

GoogleCodeExporter commented 8 years ago
But if you take integers for position values there is no possibility to save the
precise movement updates as described above. This:

position += velocity x elapsedTime;

Will not work is position is saved as integers. Because if velocity and elapsed 
time
together give a value smaller then one and position is integer the sprite will 
not
move at all. As you see there values have to be of floating point type.

I'm not sure if a float would be enough on this point anyway, but that doesn't
changes the problems you described. 

Original comment by jan.brac...@googlemail.com on 8 Apr 2008 at 5:13

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
Crud...unless the number of times the velocity has been accounted for is 
stored, 
you're right.  Guess this should be rejected.  Still, though, being able to 
"move a 
sprite one-half pixel" doesn't make any sense.  I wonder if there is a way to 
resolve this, somehow save double values internally but only allow access via 
integers?

Original comment by MetroidF...@gmail.com on 21 Apr 2008 at 12:32

GoogleCodeExporter commented 8 years ago
But the double is not very accurated, like the 3,00000001.
The BigDecimal is not primitive data type, and I don't know is it efficient or 
not,
perhaps using delta like you said is better, but how to implement it nicely, 
that
need to be think.

Original comment by pau...@gmail.com on 21 Apr 2008 at 2:48

GoogleCodeExporter commented 8 years ago
> Still, though, being able to "move a sprite one-half pixel" doesn't make any 
sense.  
> I wonder if there is a way to resolve this, somehow save double values 
internally 
> but only allow access via integers?

Oh it makes sence, if you want to create smooth, precise and accurate movement 
you
have to save carry, otherwise the unit won't move at all (The moved distance 
per move
is smaller then 1) or it will be faster/slower then it really is in some places.

> But the double is not very accurated, like the 3,00000001.

Well i don't see the problem at that point.

> The BigDecimal is not primitive data type, and I don't know is it efficient 
or not,
> perhaps using delta like you said is better, but how to implement it nicely, 
that
> need to be think.

Ohh, that way more inefficient. When using one sprite you probably won't nitice 
but
when when using a large number it will slow down.

Anyway why not just cast the double/float position when needed?
(int)sprite.x // Ultra precise :P
sprite.x // Ultra correct :D

Original comment by jan.brac...@googlemail.com on 21 Apr 2008 at 5:16