JavaFX z Arią - powrót do strony głównej

Sprite animations on ImageView (JavaFX)

Animacje wykorzystujące arkusze duszków (sprite sheets) są najczęściej używane na stronach internetowych. Wczytywanie znacznej liczby małych obrazków wymaga sporej ilości operacji i/o, a użycie tej techniki pozwala na przyśpieszenie ładowania się strony.
Tutaj dla wprawy pokazuję użycie takiej animacji na JavaFX ImageView zużyciem wziernika.

Układ modułu
Układ modułu
Sprite sheet z biegnącym chłopcem
Sprite sheet (rys. Maciej Krzywicki)
module-info.java
module m2serialanimations {

    requires jdk.jsobject;

    requires java.desktop;
    requires java.logging;
    requires java.net.http;
    requires java.scripting;
    requires java.sql;

    requires javafx.base;
    requires javafx.controls;
    requires javafx.graphics;
    requires javafx.fxml;
    requires javafx.media;
    requires javafx.swing;
    requires javafx.swt;
    requires javafx.web;

    exports p1_javafx_animations to javafx.graphics, javafx.web;
    exports p2_sprite_animations to javafx.graphics, javafx.web;
    exports utils to javafx.graphics, javafx.web;



}
Klasa Animation_Sprite_ImageView_Viewport.java
package p2_sprite_animations;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelReader;
import javafx.scene.image.WritableImage;
import javafx.stage.Stage;
import utils.AnimUtil;

public class Animation_Sprite_ImageView_Viewport extends Application {
    private ImageView iv;
    private Rectangle2D viewport;
    private Image image;
    private PixelReader pr;
    private long[] durs;
    private final int w = 98;
    private final int h = 137;

    @Override
    public void init() {
        Image image = new Image("m2serialanimations/src/resources/bieg2.png");
        durs = AnimUtil.fill4(180, 8);
        pr = image.getPixelReader();
        viewport = new Rectangle2D(0, 0, w, h);
    }

    @Override
    public void start(Stage stage) {
        try {
            Group root = new Group();
            iv = new ImageView();
            iv.setViewport(viewport);
            root.getChildren().add(iv);
            Scene scene = new Scene(root, 10 * w, h);
            stage.setScene(scene);
            stage.setTitle("Sprite Animation");
            stage.setOnCloseRequest(e -> Platform.exit());
            stage.show();
            AnimationTimer timer = new SpriteTimer();
            timer.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private class SpriteTimer extends AnimationTimer {
        long start = System.currentTimeMillis();
        int counter = 0;
        int distance = 0;

        @Override
        public void handle(long now) {
            long teraz = System.currentTimeMillis();
            long elapsed = teraz - start;
            if (elapsed > durs[counter]) {
                WritableImage im = new WritableImage(pr, counter * w, 0, w, h);
                iv.imageProperty().set(im);
                distance += 20;
                iv.setTranslateX(distance);
                if (distance > 10 * w) {
                    distance = 0;
                }
                counter++;
                if (counter > durs.length - 1) {
                    counter = 0;
                    start = System.currentTimeMillis();
                }
            }
        }
    }
}
Metoda AnimUtil.fill4()
 public static long[] fill4(long millis, int frames){
        long d = 0;
        long[] durs = new long[frames];
        for(int i =0; i< frames; i++){
            durs[i]= d;
            d += millis;
        }
        return durs;
    }

Po uruchomieniu klasy zobaczymy animację chłopca biegnącego przez ekran. Po wybiegnięciu z prawej strony chłopiec wbiega od lewej strony.

Obrazek biegnącego chłopca