如何在 JavaFX 中仅短时间显示某些内容?

How to show something in JavaFX for a brief time only?

我正在寻找一种简单的方法来在短时间内向 JavaFX 中的 ImageView 添加效果,但我还没有找到有效的方法。
这是一个游戏,玩家在平面上显示为 ImageView。当一个玩家攻击另一个玩家时,我想在被攻击的 ImageView 上显示效果,比如颜色叠加或类似的东西。
但是这样做的最佳方法是什么?有没有绕过计时器的方法或者我需要一个?

感谢您的帮助!

一般信息

有关此任务的一般信息位于:

  • JavaFX periodic background task

只做一次,只是定期做的简单版本。

照明示例

一个简单的例子,使用灯光效果让 Smurfette 在你点击她时嫉妒地变成绿色。使用了 PauseTransition。

import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

public class EnvyApp extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Image image = new Image(
                "http://icons.iconarchive.com/icons/designbolts/smurfs-movie/128/smurfette-icon.png"
        );

        ImageView imageView = new ImageView(image);

        PauseTransition hitAnimation = new PauseTransition(Duration.seconds(1));
        hitAnimation.setOnFinished(e -> imageView.setEffect(null));

        Light light = new Light.Distant();
        light.setColor(Color.PALEGREEN);
        Lighting lighting = new Lighting(light);

        imageView.setOnMouseClicked(e -> {
            imageView.setEffect(lighting);
            hitAnimation.playFromStart();
        });

        stage.setScene(new Scene(new Group(imageView), Color.AQUA));
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch();
    }
}

渐变色变化示例

单击 ImageView 时的渐变临时颜色叠加效果示例。效果展示使用时间线

颜色变化的示例基于此答案:

  • How to change color of image in JavaFX

点击的图片变成红色,然后逐渐由红变灰,变回原来的颜色。可能有更简单的方法可以做到这一点,但这是我想出的方法。

效果的时间线存储在受影响节点的属性中,但如果愿意,它可以存储在某个实例变量(例如通用 Sprite class 的属性)中。时间线已存储,因此如果您在效果完成之前单击图像,则现有时间线可以从头开始重新启动。

应用不同的效果

效果仅为示例,您可以根据自己的需要进行调整。

通用原则可用于调整任何效果(或节点)属性。您可以根据需要调整效果的实际细节。例如,点击时除了颜色调整外,您还可以通过平移使节点反弹或应用发光效果或投影效果等。

示例代码

import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.effect.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Blush extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        HitEffectGenerator effectGenerator = new HitEffectGenerator();
        Image image = new Image(
                "http://icons.iconarchive.com/icons/designbolts/smurfs-movie/128/smurfette-icon.png"
        );

        ImageView imageView = new ImageView(image);
        // try with clip on and off to see the difference . . .
        imageView.setClip(new ImageView(image));

        imageView.setOnMouseClicked(e -> effectGenerator.apply(imageView));

        stage.setScene(new Scene(new Group(imageView), Color.AQUA));
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch();
    }
}

class HitEffectGenerator {
    public void apply(ImageView target) {
        Timeline effectTimeline = (Timeline) target.getProperties().get(HitEffectGenerator.class);

        if (effectTimeline == null) {
            ColorAdjust monochrome = new ColorAdjust();
            monochrome.setSaturation(-1.0);

            ColorInput colorInput = new ColorInput(
                    0,
                    0,
                    target.getImage().getWidth(),
                    target.getImage().getHeight(),
                    Color.RED
            );

            Blend blush = new Blend(
                    BlendMode.MULTIPLY,
                    monochrome,
                    colorInput
            );

            target.setEffect(blush);

            effectTimeline = new Timeline(
                    new KeyFrame(
                            Duration.ZERO,
                            new KeyValue(monochrome.saturationProperty(), -1.0),
                            new KeyValue(colorInput.paintProperty(), Color.RED)
                    ),
                    new KeyFrame(
                            Duration.seconds(1),
                            new KeyValue(monochrome.saturationProperty(), 0.0),
                            new KeyValue(colorInput.paintProperty(), Color.TRANSPARENT)
                    )
            );

            effectTimeline.setOnFinished(e -> remove(target));
        }

        target.getProperties().put(HitEffectGenerator.class, effectTimeline);

        effectTimeline.playFromStart();
    }

    public void remove(ImageView target) {
        Timeline effectTimeline = (Timeline) target.getProperties().get(HitEffectGenerator.class);

        if (effectTimeline != null) {
            target.setEffect(null);
            target.getProperties().remove(HitEffectGenerator.class);
            effectTimeline.stop();
        }
    }
}

各种点击动画效果

参见:

这些示例很旧并且使用了已弃用的构建器 API,但很容易转换为使用构造函数和设置器而不是构建器的现代代码。