使用 lwjgl 为对象设置动画的正确框架?
Proper framework for animating objects with lwjgl?
我的目标是在屏幕上绘制二维 UI 元素并为其设置动画。问题是,我不确定如何在不占用大量 space 的情况下为其设置动画。
这就是我的方法在 0, 0 处绘制一个宽度和高度为 50
的红色矩形的样子
public void render() {
Gui.drawRect(0, 0, 50, 50, Color.red); // Drawing an object would look something like this
}
现在,我要做的是定义一个变量,例如 rectanglePos = 0
,并将其添加到我想要更改的轴上。 drawRect(0 + rectanglePos, 0, 50, 50, Color.red);
现在,当我想为矩形设置动画时,我创建了一个新线程并从那里为其设置了动画。
public void render() {
Gui.drawRect(0 + rectanglePos, 0, 50, 50, Color.red); // Drawing an object would look something like this
}
public void animate() {
Thread t = new Thread(() -> {
float target = 50;
for (int i = 0; i < 50; i++) {
//ease(int start, int end, float time, EasingType type)
rectanglePos = AnimationUtil.ease(0, target, 5, EasingType.CubicInOut);
}
});
t.start();
}
这里的这个例子显然很糟糕。我的问题是,构建它的最佳方式是什么?
使用 System.currentTimeMillis()
,我们可以使用缓动函数为屏幕上的二维 UI 元素设置动画,无需线程或其他花哨的东西。假设我们希望动画在 x 轴上移动,从 10 开始到 50 结束。假设我们知道何时开始和持续时间,我们就可以计算出动画何时结束。
假设time
等于当前时间,startTime
等于我们开始的时间,依此类推...
在一个单独的 class 中,我们需要一些方法来帮忙。一种方法returns我们动画的进度。有关标准缓动函数的列表,请参阅 Easing Functions。另一种方法将此值转换为开始和结束像素。
当前进度等于(time - startTime) / duration
。这已经为我们提供了放入 ease 方法的价值。 ease 方法 returns 一个介于 0.0
和 1.0
之间的值,因此我们要做的就是将其“转换”为像素。公式为:(end - start) * ease(alpha)
.
下面是该概念的实现。没有什么是完美的。
long startTime = 0L;
public void animate() {
this.startTime = System.currentTimeMillis();
}
// 10, 10 -> 50, 50
public void render() {
// 1000 milliseconds = 1 Second
drawRect(10 + Ease.toPixels(10, 50,Ease.getProgress(this.startTime, 1000L)), 10, ... etc);
}
帮助 class:
// easeInOutCubic
public static float ease(float alpha) {
return (float) (alpha < 0.5 ? 4 * alpha * alpha * alpha : 1 - Math.pow(-2 * alpha + 2, 3) / 2);
}
public static float getProgress(long startTime, float duration) {
long time = System.currentTimeMillis();
float progress = (time - startTime) / duration;
if (progress <= 0.0F) return 0.0F;
if (progress >= 1.0F) return 1.0F;
return progress;
}
public static int toPixels(float start, float end, float alpha) {
return (int) ((end - start) * ease(alpha));
}
我的目标是在屏幕上绘制二维 UI 元素并为其设置动画。问题是,我不确定如何在不占用大量 space 的情况下为其设置动画。 这就是我的方法在 0, 0 处绘制一个宽度和高度为 50
的红色矩形的样子public void render() {
Gui.drawRect(0, 0, 50, 50, Color.red); // Drawing an object would look something like this
}
现在,我要做的是定义一个变量,例如 rectanglePos = 0
,并将其添加到我想要更改的轴上。 drawRect(0 + rectanglePos, 0, 50, 50, Color.red);
现在,当我想为矩形设置动画时,我创建了一个新线程并从那里为其设置了动画。
public void render() {
Gui.drawRect(0 + rectanglePos, 0, 50, 50, Color.red); // Drawing an object would look something like this
}
public void animate() {
Thread t = new Thread(() -> {
float target = 50;
for (int i = 0; i < 50; i++) {
//ease(int start, int end, float time, EasingType type)
rectanglePos = AnimationUtil.ease(0, target, 5, EasingType.CubicInOut);
}
});
t.start();
}
这里的这个例子显然很糟糕。我的问题是,构建它的最佳方式是什么?
使用 System.currentTimeMillis()
,我们可以使用缓动函数为屏幕上的二维 UI 元素设置动画,无需线程或其他花哨的东西。假设我们希望动画在 x 轴上移动,从 10 开始到 50 结束。假设我们知道何时开始和持续时间,我们就可以计算出动画何时结束。
假设time
等于当前时间,startTime
等于我们开始的时间,依此类推...
在一个单独的 class 中,我们需要一些方法来帮忙。一种方法returns我们动画的进度。有关标准缓动函数的列表,请参阅 Easing Functions。另一种方法将此值转换为开始和结束像素。
当前进度等于(time - startTime) / duration
。这已经为我们提供了放入 ease 方法的价值。 ease 方法 returns 一个介于 0.0
和 1.0
之间的值,因此我们要做的就是将其“转换”为像素。公式为:(end - start) * ease(alpha)
.
下面是该概念的实现。没有什么是完美的。
long startTime = 0L;
public void animate() {
this.startTime = System.currentTimeMillis();
}
// 10, 10 -> 50, 50
public void render() {
// 1000 milliseconds = 1 Second
drawRect(10 + Ease.toPixels(10, 50,Ease.getProgress(this.startTime, 1000L)), 10, ... etc);
}
帮助 class:
// easeInOutCubic
public static float ease(float alpha) {
return (float) (alpha < 0.5 ? 4 * alpha * alpha * alpha : 1 - Math.pow(-2 * alpha + 2, 3) / 2);
}
public static float getProgress(long startTime, float duration) {
long time = System.currentTimeMillis();
float progress = (time - startTime) / duration;
if (progress <= 0.0F) return 0.0F;
if (progress >= 1.0F) return 1.0F;
return progress;
}
public static int toPixels(float start, float end, float alpha) {
return (int) ((end - start) * ease(alpha));
}