javaeasing

Easing a value to another value overtime in java


I want to ease a value overtime, for example I have the number 85, I want to ease it to 180 slow / fast depending on a certain delay, here's a visual example:

TIME:    0sec   0.25sec   0.5sec    0.75sec   1sec
VALUE:   85     100       126       140       180

What I know I need is System.currentTimeMillis(), however I do not know how to use it properly to determine what is the next value in the next millisecond

I am trying to implement is a easing method to yaw and pitch within Minecraft so it is not just an instant yaw and pitch change.

If you need any other info, feel free to ask.

Code I tried:

public void easeValue(int delay) {
         oldValue = (float) Math.ceil((System.currentTimeMillis() + delay) / oldValue);
         if (oldValue >= targetValue) {
             System.out.println("target reached");
         }
    }

( I had no idea what I was doing )


Solution

  • One problem with System.cTM is that it changes as your clock setting changes. This does happen - usually servers and computers alike run NTP daemons which check current time against networked time servers and will adjust if need be. Ordinarily, daylight savings or switching time zones should not affect it, though, and good NTP daemons will smear changes out which means your easing will simply be slow or fast, instead of completely crash.

    Nevertheless, one easy way out is to use System.nanoTime instead which is more or less 'CPU uptime' (I'm oversimplifying), and isn't affected whatsoever by any time daemons or by the user changing the time by hand.

    One small complication is that nanoTime can overflow, and you'll need to take that into consideration.

    Your snippet doesn't take into account any notion of a 'start point'. You can't write a formula to calculate where you are along the linear progression from 85 to 180 unless you know at what point in time '85' ought to be returned, and at what point '180'. The method can therefore obviously never be just ease(int delay). You need to store the 'start and end' numbers (85 and 180 in your example) someplace, and the same applies to the start and end time, which need to be turned into absolute numbers at some moment in time (when you want the easing to start). It's java, so let's do what java is good at, and make an object to represent this state.

    Here's a basic idea:

    import java.util.concurrent.TimeUnit;
    
    public class Easing {
        private final long duration; // in nanos
        private final long startTime;
        private final long endTime;
        private final int startValue;
        private final int endValue;
    
        private Easing(long duration, int startValue, int endValue) {
            if (duration < 1) throw new IllegalArgumentException("duration not positive");
            this.duration = duration;
            this.startTime = System.nanoTime();
            this.endTime = this.start + duration;
            this.startValue = startValue;
            this.endValue = endValue;
        }
    
        public static Easing ofSeconds(int seconds, int startValue, int endValue) {
            return new Easing(TimeUnit.SECONDS.toNanos(seconds), startValue, endValue);
        }
    
        public int getCurrentValue() {
            long now = System.nanoTime();
            long delta = now - startTime;
            long range = endTime - startTime;
    
            if (delta > range) return endValue;
            double p = 1.0 * delta / range;
            int valRange = endValue - startValue;
            return (int) (0.5 + (p * valRange) + startValue);
        }
    }
    

    Let's see it in action:

    public static void main(String[] args) throws Exception {
        Easing easing = Easing.ofSeconds(10, 80, 180);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 55; i++) {
            long mark = System.currentTimeMillis();
            System.out.printf("At [%d]: %d\n", mark - start, easing.getCurrentValue());
            Thread.sleep(200);
        }
    }
    
    At [0]: 80
    At [229]: 82
    At [430]: 84
    At [633]: 86
    At [839]: 88
    At [1042]: 90
    At [1244]: 92
    At [1448]: 94
    At [1651]: 97
    At [1856]: 99
    At [2060]: 101
    At [2265]: 103
    At [2468]: 105
    At [2673]: 107
    At [2878]: 109
    At [3080]: 111
    At [3284]: 113
    At [3489]: 115
    At [3693]: 117
    At [3897]: 119
    At [4101]: 121
    At [4306]: 123
    At [4510]: 125
    At [4715]: 127
    At [4919]: 129
    At [5125]: 131
    At [5329]: 133
    At [5531]: 135
    At [5735]: 137
    At [5937]: 139
    At [6139]: 141
    At [6342]: 143
    At [6544]: 145
    At [6749]: 147
    At [6952]: 150
    At [7156]: 152
    At [7361]: 154
    At [7565]: 156
    At [7770]: 158
    At [7975]: 160
    At [8178]: 162
    At [8380]: 164
    At [8581]: 166
    At [8785]: 168
    At [8986]: 170
    At [9188]: 172
    At [9392]: 174
    At [9595]: 176
    At [9797]: 178
    At [10002]: 180
    At [10207]: 180
    At [10411]: 180
    At [10613]: 180
    At [10814]: 180
    At [11019]: 180