java - कैसे लाइन एनीमेशन चिकनी बनाने के लिए?




animation timer (2)

मैं जावा में एक साधारण एनीमेशन बना रहा हूं और मैं इसे यथासंभव चिकनी बनाने की कोशिश कर रहा हूं।

मैं केवल * का उपयोग करता हूँ। प्रत्येक आकृति वस्तु के डबल आंतरिक वर्ग और मैं ग्राफिक्स 2 डी ऑब्जेक्ट्स में एंटीअलियासिंग सेट करता हूं। यह सब तब तक काम करता है जितना मैं केवल भर () विधि का उपयोग करता हूं, लेकिन अगर मैं एक ही आकृति के समान लाइनों को आकर्षित करने के लिए ड्रॉ () विधि का उपयोग करता हूं तो इन लाइनों के एनीमेशन तड़का हुआ है - पिक्सेल द्वारा पिक्सेल

कैनवास पर मेरे प्रत्येक आयताकार में स्वयं को पेंट करने के लिए यह विधि होती है इसे हर 20ms में स्थानांतरित किया जाता है और पूरे कैनवास टाइमर और टाइमर लिस्टनर का उपयोग करके फिर से दोहराया जाता है।

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class AnimationTest {
    public static void main(String[] args) {
        JFrame frm = new JFrame("Test");
        frm.setBounds(200, 200, 400, 400);
        frm.setResizable(false);
        frm.setLocationRelativeTo(null);

        AnimationCanvas a = new AnimationCanvas();
        frm.add(a);

        frm.setVisible(true);

        a.startAnimation();
    }
}

class AnimationCanvas extends JPanel {

    SimpleSquare[] squares = new SimpleSquare[2];

    AnimationCanvas() {

        squares[0] = new SimpleSquare(50, 80, true);
        squares[1] = new SimpleSquare(160, 80, false);

    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        for (SimpleSquare c : squares) {
            c.paintSquare(g);
        }
    }

    Timer t;
    public void startAnimation() {
        t = new Timer(30, new Animator());
        t.start();
    }

    private class Animator implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            squares[0].y += 0.10;
            squares[1].y += 0.10;
            repaint();
        }
    }
}


class SimpleSquare {
    double x;
    double y;
    Color color = Color.black;
    boolean fill;

    SimpleSquare(double x, double y, boolean fill) {
        this.x = x;
        this.y = y;
        this.fill = fill;
    }

    void paintSquare(Graphics g) {
        ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        Shape s = new Rectangle.Double(x, y, 100, 100);

        g.setColor(color);
        ((Graphics2D) g).setStroke(new BasicStroke(2));

        if (fill) {
            ((Graphics2D) g).fill(s);
        } else {
            ((Graphics2D) g).draw(s);
        }
    }
}

क्या इस समस्या को दूर करने के लिए कोई उपाय है? मैं थोड़ी देर के लिए चारों ओर देखा


आपके पास:

private class Animator implements ActionListener {
       @Override
       public void actionPerformed(ActionEvent e) {
           squares[0].y += 0.10;
           squares[1].y += 0.10;
           repaint();
       }
   }

तथा

public void startAnimation() {
    t = new Timer(30, new Animator());
    t.start();
}

लेकिन आप इसे बदलकर ही हासिल कर सकते हैं

private class Animator implements ActionListener {
       @Override
       public void actionPerformed(ActionEvent e) {
           squares[0].y += 1;
           squares[1].y += 1;
           repaint();
       }
   }

तथा

public void startAnimation() {
    t = new Timer(300, new Animator());
    t.start();
}

जो वही करता है, लेकिन 10 गुना कम लूप करता है।

मैंने कोड का परीक्षण नहीं किया लेकिन यह एक कोशिश के लायक है

उचित समाधान MadProgrammer द्वारा प्रदान किया जाता है, जहां वह इसके द्वारा देरी और ऑफसेट को मापता है।


मैं इस छोटे से परीक्षण को एक साथ रखता हूं और मुझे कोई महत्व नहीं मिला, मैं मूल रूप से 50 एफपीएस बनाए रखने में सक्षम था, यहां तक ​​कि 1000 आयत के साथ ही यादृच्छिक दिशाओं में सभी गतिशील दिशाओं में चलते हैं।

public class SimpleAnimationEngine {

    public static void main(String[] args) {
        new SimpleAnimationEngine();
    }

    public SimpleAnimationEngine() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                AnimationPane pane = new AnimationPane();

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(pane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                pane.init();
                pane.start();
            }

        });
    }

    public static class AnimationPane extends JPanel implements AnimationCanvas {

        private AnimationModel model;

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        public AnimationModel getModel() {
            return model;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            for (Animatable animatable : getModel().getAnimatables()) {
                animatable.paint(g2d);
            }
            g2d.dispose();
        }

        @Override
        public synchronized void updateState() {

            Runnable update = new Runnable() {
                @Override
                public void run() {
                    AnimationModel model = getModel();
                    for (Animatable animatable : model.getAnimatables()) {
                        animatable.copy();
                    }
                    repaint();
                }

            };

            if (EventQueue.isDispatchThread()) {
                update.run();
            } else {
                try {
                    EventQueue.invokeAndWait(update);
                } catch (InterruptedException | InvocationTargetException ex) {
                    ex.printStackTrace();
                }
            }
        }

        public void init() {
            model = new DefaultAnimationModel();
            for (int index = 0; index < 1000; index++) {
                model.add(new AnimatableRectangle(this));
            }
            updateState();
        }

        public void start() {
            AnimationEngine engine = new AnimationEngine(this, getModel());
            engine.start();
        }

    }

    public static interface Animatable {

        public void copy();

        public void update(AnimationCanvas canvas, float progress);

        public void paint(Graphics2D g2d);

    }

    public static class AnimationEngine extends Thread {

        private AnimationModel model;
        private AnimationCanvas canvas;

        public AnimationEngine(AnimationCanvas canvas, AnimationModel model) {
            setDaemon(true);
            setName("AnimationThread");
            this.model = model;
            this.canvas = canvas;
        }

        public AnimationCanvas getCanvas() {
            return canvas;
        }

        public AnimationModel getModel() {
            return model;
        }

        @Override
        public void run() {
            float progress = 0;
            long cylceStartTime = System.currentTimeMillis();
            long cylceEndTime = cylceStartTime + 1000;
            int updateCount = 0;
            while (true) {
                long frameStartTime = System.currentTimeMillis();
                getModel().update(getCanvas(), progress);
                getCanvas().updateState();
                long frameEndTime = System.currentTimeMillis();
                long delay = 20 - (frameEndTime - frameStartTime);
                if (delay > 0) {
                    try {
                        sleep(delay);
                    } catch (InterruptedException ex) {
                    }
                }
                long now = System.currentTimeMillis();
                long runtime = now - cylceStartTime;
                progress = (float)runtime / (float)(1000);
                updateCount++;
                if (progress > 1.0) {
                    progress = 0f;
                    cylceStartTime = System.currentTimeMillis();
                    cylceEndTime = cylceStartTime + 1000;
                    System.out.println(updateCount + " updates in this cycle");
                    updateCount = 0;
                }
            }
        }

    }

    public interface AnimationCanvas {

        public void updateState();

        public Rectangle getBounds();

    }

    public static interface AnimationModel {

        public void update(AnimationCanvas canvas, float progress);

        public void add(Animatable animatable);

        public void remove(Animatable animatable);

        public Animatable[] getAnimatables();

    }

    public static class AnimatableRectangle implements Animatable {

        private Rectangle bounds;
        private int dx, dy;
        private Rectangle copyBounds;
        private Color foreground;
        private Color backColor;

        public AnimatableRectangle(AnimationCanvas canvas) {
            bounds = new Rectangle(10, 10);
            Rectangle canvasBounds = canvas.getBounds();
            bounds.x = canvasBounds.x + ((canvasBounds.width - bounds.width) / 2);
            bounds.y = canvasBounds.y + ((canvasBounds.height - bounds.height) / 2);

            dx = (getRandomNumber(10) + 1) - 5;
            dy = (getRandomNumber(10) + 1) - 5;

            dx = dx == 0 ? 1 : dx;
            dy = dy == 0 ? 1 : dy;

            foreground = getRandomColor();
            backColor = getRandomColor();

        }

        protected int getRandomNumber(int range) {
            return (int) Math.round(Math.random() * range);
        }

        protected Color getRandomColor() {
            return new Color(getRandomNumber(255), getRandomNumber(255), getRandomNumber(255));
        }

        @Override
        public void copy() {
            copyBounds = new Rectangle(bounds);
        }

        @Override
        public void update(AnimationCanvas canvas, float progress) {
            bounds.x += dx;
            bounds.y += dy;
            Rectangle canvasBounds = canvas.getBounds();
            if (bounds.x + bounds.width > canvasBounds.x + canvasBounds.width) {
                bounds.x = canvasBounds.x + canvasBounds.width - bounds.width;
                dx *= -1;
            }
            if (bounds.y + bounds.height > canvasBounds.y + canvasBounds.height) {
                bounds.y = canvasBounds.y + canvasBounds.height - bounds.height;
                dy *= -1;
            }
            if (bounds.x < canvasBounds.x) {
                bounds.x = canvasBounds.x;
                dx *= -1;
            }
            if (bounds.y < canvasBounds.y) {
                bounds.y = canvasBounds.y;
                dy *= -1;
            }
        }

        @Override
        public void paint(Graphics2D g2d) {
            g2d.setColor(backColor);
            g2d.fill(copyBounds);
            g2d.setColor(foreground);
            g2d.draw(copyBounds);
        }

    }

    public static class DefaultAnimationModel implements AnimationModel {

        private List<Animatable> animatables;

        public DefaultAnimationModel() {
            animatables = new ArrayList<>(25);
        }

        @Override
        public synchronized void update(AnimationCanvas canvas, float progress) {
            for (Animatable animatable : animatables) {
                animatable.update(canvas, progress);
            }
        }

        @Override
        public synchronized void add(Animatable animatable) {
            animatables.add(animatable);
        }

        @Override
        public synchronized void remove(Animatable animatable) {
            animatables.remove(animatable);
        }

        @Override
        public synchronized Animatable[] getAnimatables() {
            return animatables.toArray(new Animatable[animatables.size()]);
        }

    }

}

अद्यतन करें

आप जिस सबसे बड़ी समस्या का सामना करने जा रहे हैं वह इस बात से संबंधित है कि स्क्रीन पूरी संख्या में काम करती है ...

private class Animator implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        squares[0].y += 1;
        squares[1].y += 1;
        repaint();
    }
}

मुझे विश्वास है कि दोनों वर्ग वास्तव में "चिड़चिड़ाहट" हैं, लेकिन क्योंकि ड्रान स्क्वायर का शरीर की इस तरह की स्पष्ट कमी है, यह अधिक खड़ा है। मैं इस परीक्षा को बिना किसी समस्या के 24fps लगभग चलाता हूं।





smooth