Skip to content
Advertisement

Proper framework for animating objects with lwjgl?

My goal is to draw and animate 2D UI elements on the screen. The problem is, I’m not exactly sure how I can animate it without taking up a lot of space doing so. This is what my method would look like to draw a red rectangle at 0, 0 with a width and height of 50

public void render() {
    Gui.drawRect(0, 0, 50, 50, Color.red); // Drawing an object would look something like this
}

Now, what I would do is define a variable such as rectanglePos = 0 and add that to the axis that I want to change. drawRect(0 + rectanglePos, 0, 50, 50, Color.red); Now when I want to animate the rectangle, I create a new Thread and animate it from there.

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

This example here clearly is just bad. My question is, what is the best way to go about structuring this?

Advertisement

Answer

Using System.currentTimeMillis(), we can animate 2D UI elements on the screen with easing functions without Threads or other fancy stuff. Let’s assume that we want the animation to move on the x-axis, starting at 10 and ending at 50. Assuming we know when to start and the duration, we can calculate when the animation ends.

Let’s say time is equal to the current time, and startTime is equal to the time we start, and so on… In a separate class, we need a few methods to help out. One method returns the progress of our animation. See Easing Functions for a list of standard easing functions. Another method converts this value into the start and end pixels.

The current progress would be equal to (time - startTime) / duration. This already gives us the value to put into our ease method. The ease method returns a value between 0.0 and 1.0, so all we have to do is “convert” this into the pixels. The formula would be: (end - start) * ease(alpha).

Here’s the implementation of that concept. It’s nothing perfect.

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

Helping 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));
}
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement