【问题标题】:Why does the locaton of my animated circles flicker?为什么我的动画圈子的位置会闪烁?
【发布时间】:2020-09-29 21:40:30
【问题描述】:

通过trident,我创建了一个(看似)简单的动画。一些圆圈正在从底部移动到顶部,然后通过正弦插值再次返回:

动画本身似乎可以正常工作,但是有一两帧我的所有球体都闪烁到最高位置。

为什么会闪烁?谁在用看似错误的值调用setY 方法?

我制作了一个测试类来重现该行为。您需要radiance-trident 3.0 才能使其工作:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JDialog;
import javax.swing.JPanel;

import org.pushingpixels.trident.api.Timeline;
import org.pushingpixels.trident.api.Timeline.RepeatBehavior;
import org.pushingpixels.trident.api.ease.TimelineEase;
import org.pushingpixels.trident.api.swing.SwingRepaintTimeline;

public class MovingSpheresTest extends JDialog {

    private final double sphereRadius = 3d;

    private final double sphereCount = 12d;

    private final double helixHeight = 100d;

    private final double size = 200d;

    private final double animationSpeed = 0.5d;

    private List<CenteredSphere> spheres;

    private SwingRepaintTimeline repaintTimeline;

    private final JPanel contentPanel = new JPanel() {
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            paintFrame((Graphics2D) g);
        }

        private void paintFrame(Graphics2D g) {
            Graphics2D create = (Graphics2D) g.create();
            try {
                create.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                create.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                create.setColor(Color.BLACK);
                for (CenteredSphere centeredSphere : spheres) {
                    create.fill(centeredSphere);
                }
            } finally {
                create.dispose();
            }
        }
    };

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        try {
            MovingSpheresTest dialog = new MovingSpheresTest();
            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            dialog.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Create the dialog.
     */
    public MovingSpheresTest() {
        setBounds(100, 100, 450, 300);
        getContentPane().setLayout(new BorderLayout());
        contentPanel.setLayout(new FlowLayout());
        getContentPane().add(contentPanel, BorderLayout.CENTER);
        installSpheres();
        installRepaintTimeline();
    }

    private void installSpheres() {
        double helixRadius = helixHeight / 2;
        double effectiveWidth = size - (2 * sphereRadius);
        double sphereDistance = effectiveWidth / (sphereCount - 1);
        double sphereCenterX = sphereRadius;
        double sphereCenterY = size / 2d;
        double sphereCenterYInitial = sphereCenterY - helixRadius;

        spheres = new ArrayList<>();
        for (int sphereIndex = 0; sphereIndex < sphereCount; sphereIndex++) {
            CenteredSphere sphere = new CenteredSphere(sphereCenterX, sphereRadius);
            spheres.add(sphere);
            sphereCenterX += sphereDistance;
            Timeline.builder()
                    .addPropertyToInterpolate(Timeline.<Double>property("y").on(sphere).from(sphereCenterYInitial)
                            .to(sphereCenterY + helixRadius))
                    .setEase(new FullSine((float) (sphereIndex * 2 * Math.PI / sphereCount)))
                    .setDuration((long) (animationSpeed * 3000d)).playLoop(RepeatBehavior.LOOP);
        }

    }

    private class FullSine implements TimelineEase {

        private float horizontalOffset;

        private FullSine(float horizontalOffset) {
            this.horizontalOffset = horizontalOffset;
        }

        @Override
        public float map(float durationFraction) {
            return ((float) Math.sin(durationFraction * Math.PI * 2f + horizontalOffset) + 1f) / 2f;
        }
    }

    private void installRepaintTimeline() {
        repaintTimeline = SwingRepaintTimeline.repaintBuilder(contentPanel).build();
        repaintTimeline.playLoop(RepeatBehavior.LOOP);
    }

    public class CenteredSphere extends Ellipse2D.Double {

        private double sphereCenterX;
        private double sphereRadius;

        public CenteredSphere(double sphereCenterX, double sphereRadius) {
            this.sphereCenterX = sphereCenterX;
            this.sphereRadius = sphereRadius;
        }

        public void setY(double y) {
            setFrameFromCenter(sphereCenterX, y, sphereCenterX + sphereRadius, y + sphereRadius);
        }
    }
}

【问题讨论】:

    标签: java swing animation trident


    【解决方案1】:

    如上所述here 和固定here

    这很有趣。这是因为基本假设 TimelineEase 始终映射 [0.0-1.0] 区间而不“扭曲”端点。在这种特殊情况下,在每个动画循环期间,自定义 FullSine 用于根据球体偏移重新映射该间隔,但在循环重置期间,“结束”点不会被映射。

    【讨论】:

      猜你喜欢
      • 2022-12-10
      • 2020-09-19
      • 2012-03-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多