Java2D time-based movement

3

I'm trying to move an object using Java2D but I'm having some problems, I have following method:

public void logics() throws Exception{
    before = System.nanoTime();
    loop.logics(diff);
    after = System.nanoTime();
    diff = after - before;
}

Within method loop.logics(long delta) I have the following code:

double ddelta = delta/1000000000.0;
x += speed*ddelta;// delta é a variação em segundos
System.out.println(x);

x and speed start at 100, however the result I see on output is:

...
101.01591999999998
101.02638559999998
101.03550849999998
101.04340709999998
101.06836669999998
101.13834839999998
101.14830059999998
101.15935859999999
101.16879739999999
101.18246199999999
101.19245369999999
101.20157659999998
...

Giving a print on delta to see that it is very low:

83330
80961
73063
80566
....

The intent is to make x vary from speed units per second. In a second, the sum of all% w / o% 's obtained must be 1e9, so the sum of all increments in% w /% must be% w /%, but as I have shown, this is not the case if someone Can you help me? I appreciate it.

    
asked by anonymous 06.06.2016 / 04:58

2 answers

1

I made some changes to the loop: The first big mistake is that I was ignoring the drawing phase to do the calculations (it happens right after the call to logics() ), which is a big mistake since the rendering part it takes a lot of time, the second was the way I calculated diff , the most accurate way to do this would be just before the method call'logics (long delta) ', before also calculating before , then method logics() looks like this:

@Override
public void logics() throws Exception{
    after =  System.nanoTime();
    diff = after - before;
    before = System.nanoTime();
    loop.logics(diff);
}

With these changes the movement is really good: using different values of speed : 1, 10 and 100 of to see that the variation of x is close to expected: it increases approximately% / p>     

07.06.2016 / 01:49
1

It seems to me that you are running into two problems.

The first problem is that although you're using System.nanoTime() , the clock on your computer and / or operating system should not have enough precision / resolution to measure the time in nanoseconds. Incidentally, as the javadocs of this method show:

  

This method provides nanosecond precision, but not necessarily nanosecond resolution (that is, how often the value changes) - no guarantees are made except that the resolution is at least as good as that of currentTimeMillis() .

That translating into Portuguese is:

  

This method provides nanosecond precision, but not necessarily a nanosecond resolution (that is, how often the value changes) - no guarantee is made except that the resolution will be at least as good as that of currentTimeMillis() .

The second problem I see is that you make calculations that may lose precision with double . The double represents a number with a finite precision, since it occupies only 64 bits, varying the position of the decimal point. This means that small numbers can lose bits of information / accuracy when they are added up with large numbers. For example:

public class Calculo {
    public static void main(String[] args) {
        double x = 10 * 1e9;
        double y = 10 * 1e-9;
        System.out.println(x);
        System.out.println(x + y);
        System.out.println(x == x + y);
        double a = 10 * 1e7;
        double b = 10 * 1.557e-8;
        System.out.println(a + b);
    }
}

Here's the output:

1.0E10
1.0E10
true
1.0000000000000015E8

This shows that in this case, the small number ( y ) ended up being totally neglected when it was added to the big number ( x ). This is due to how double rounds their values so that they fit in their representation. In the case of a + b , some bits of b ended up being cut so that they could be summed. So what's happening in your code is that by summing multiple values with many precision decimal (actually binary) decimal places, the least significant bits get discounted so that the value fits within the 64 bits of double .

Finally, the fact that you're using (double)diff/1000000000.0 causes you to get double rounding problems. It would be best to work with% s of% s representing values in nanoseconds and only convert them in seconds when you show them somewhere.

Furthermore, the fact that your method is long instead of loop.logics(float delta) makes me suspect that there must be other places where your program suffers with rounding problems when converting loop.logics(double delta) (with 64 bits of information ) to double (with 32 bits of information). Incidentally, was it not for the compiler to give you an error about possible loss of precision when passing float to a method whose parameter is double ?

    
06.06.2016 / 12:27