首页 > 解决方案 > 在java中将一个值缓和到另一个值超时

问题描述

我想缓和一个值超时,例如我有数字 85,我想根据一定的延迟将它缓和到 180 慢/快,这是一个视觉示例:

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

我知道我需要的是System.currentTimeMillis(),但是我不知道如何正确使用它来确定下一毫秒的下一个值是什么

我正在尝试实现的是一种在 Minecraft 中偏航和俯仰的缓和方法,因此它不仅仅是即时的偏航和俯仰变化。

如果您需要任何其他信息,请随时询问。

我试过的代码:

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

(我不知道我在做什么)

标签: javaeasing

解决方案


一个问题System.cTM是它会随着您的时钟设置的变化而变化。这确实会发生 - 通常服务器和计算机都运行 NTP 守护程序,这些守护程序会根据联网时间服务器检查当前时间,并在需要时进行调整。通常,夏令时或切换时区不应该影响它,而且好的 NTP 守护进程会抹掉变化,这意味着你的缓动只会变慢或变快,而不是完全崩溃。

尽管如此,一种简单的方法是使用System.nanoTime或多或少的“CPU正常运行时间”(我过于简单化了),并且不受任何时间守护程序或用户手动更改时间的影响。

一个小问题是 nanoTime 可能会溢出,您需要考虑到这一点。

您的代码段没有考虑“起点”的任何概念。你不能写一个公式来计算你在从 85 到 180 的线性进展中的位置,除非你知道应该在什么时间点返回“85”,以及在什么点返回“180”。因此,该方法显然永远不会是公正ease(int delay)的。您需要将“开始和结束”数字(在您的示例中为 85 和 180)存储在某个地方,这同样适用于开始和结束时间,需要在某个时刻将其转换为绝对数字(当您想要轻松开始)。是java,所以我们就做java擅长的事情,做一个对象来表示这个状态。

这是一个基本的想法:

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);
    }
}

让我们看看它的实际效果:

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

推荐阅读