Вращение графики с использованием arc2d - PullRequest
0 голосов
/ 21 января 2019

Я пытаюсь сделать игру в рулетку в казино, поэтому для этого я сделал свою рулетку, используя пакет Arc2D.

Мой код ниже

package roulette;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Arc2D;
import java.awt.geom.AffineTransform;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class RouletteInterface extends JPanel{
    public int spinValue = 0;
    public void paint(Graphics g){       
        Graphics2D g2d = (Graphics2D)g;
        paintRoulette(g2d);

    }

    public void paintRoulette(Graphics2D g2d) {
        RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHints(hints);
        AffineTransform at = AffineTransform.getTranslateInstance(10, 10);
        at.rotate(spinValue, 10, 10);


        double angle = 360 / 36.9;
        double startAngle = 0;
        int color = 0;
        for(int i = 0; i < 37; i++) {
            if(i == 0) {
                g2d.setColor(Color.GREEN);
            } else {
                if(color == 0) {
                    g2d.setColor(Color.BLACK);
                    color = 1;
                } else {
                    g2d.setColor(Color.RED);
                    color = 0;
                }
            }

            g2d.fill(new Arc2D.Double(100, 100, 300, 300, startAngle, angle, Arc2D.PIE));
            startAngle += angle;
        }

        g2d.transform(at);

        Timer timer = new Timer(5, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                spinValue += 0.01;
                repaint();
            }
        });
        timer.start();
    }
}

ВКороче говоря, я не использую общий путь, потому что я хочу заполнить каждую дугу цветом красный / зеленый или черный, как в оригинальной рулетке, и для вращения я попытался использовать таймер для увеличения spinValue (это работало для меня, но когда я использовал общий путь) для AfinneTransformation, но когда я запускаю код, ничего не происходит.Показывает только рулетку без анимации.Что я могу сделать?

Заранее спасибо.

1 Ответ

0 голосов
/ 21 января 2019

Живопись и графика в целом являются довольно сложными темами, Java / Swing делает хорошую работу по «объединению» API-интерфейсов в нечто простое в использовании, но все же требует времени и усилий для изучения и полного понимания.

Я бы настоятельно рекомендовал иметь Выполнение пользовательской рисования , Рисование в AWT и Swing и 2D-графика и отмеченные JavaDocs, как вы вернетесь им регулярно (я все еще делаю)

Существует множество проблем, которые усложняют вашу жизнь.

Начиная с ...

public void paint(Graphics g){       
    Graphics2D g2d = (Graphics2D)g;
    paintRoulette(g2d);

}

Вы должны предпочесть переопределение paintComponent вместо paint, рисование - сложный процесс, и вам нужно тщательно выбирать точку входа. Кроме того, вы всегда должны вызывать методы рисования super, если только вы не абсолютно уверены в том, что можете самостоятельно взять на себя его основные функции.

В вашем случае вы также должны сделать копию контекста Graphics, прежде чем передавать его в paintRoulette, так как Graphics является общим ресурсом, и применяемые вами преобразования вызовут проблемы для всего, что раскрашивается после вашего компонента.

Трансформации ...

AffineTransform at = AffineTransform.getTranslateInstance(10, 10);
at.rotate(spinValue, 10, 10);

Это несколько интересно. Вы создаете перевод 10x10, который будет перемещать исходную точку контекста Graphics. Затем вы применяете вращение, привязанное к 10x10.

Причина, по которой я это упоминаю, в том, что вы потом делаете ...

g2d.fill(new Arc2D.Double(100, 100, 300, 300, startAngle, angle, Arc2D.PIE));

Это означает, что дуга смещена на 110x110 от угла компонента (добавьте в ваш перевод), и вы будете вращаться вокруг точки 20x20 от верхнего / левого угла компонента (добавьте в свой перевод) ) ... это странно для меня, потому что центр колеса на самом деле находится в 250x250 (из верхнего / левого угла компонента), что может вызвать один очень странный эффект.

Наконец, вы применяете преобразование ПОСЛЕ завершения рисования И затем создаете Timer внутри метода рисования ...

Картина выполнена в сериале. Таким образом, одна операция будет влиять на следующую, это будет означать, что вам нужно будет применить преобразование ПЕРЕД тем, как вы что-то рисуете (что вы хотите преобразовать)

Вам также необходимо понимать, что вы не контролируете процесс рисования, это означает, что ваш компонент может быть окрашен по любой причине в любое время без вашего взаимодействия. Это означает, что вы могли бы бесконечное число Timer с за очень маленький промежуток времени.

Вместо этого ваш таймер должен управляться извне из paint процесса.

Еще одна вещь, которая заняла у меня некоторое время, чтобы потренироваться - это ...

public int spinValue = 0;
//...
Timer timer = new Timer(5, new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        spinValue += 0.01;
        repaint();
    }
});

Вы объявляете spinValue как int, но добавляете к нему значение с плавающей запятой, это будет иметь эффект усечения десятичного компонента, поэтому значение ВСЕГДА будет 0.

Кроме того, AffineTransform#rotate ожидает, что углы будут в радианах, а не в градусах. Не уверен, что это важно, но вы должны знать об этом.

Пример запуска ...

Хорошо, после применения вышесказанного код "может" выглядеть примерно так ...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Test {

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

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new RoulettePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class RoulettePane extends JPanel {

        private double spinValue = 0;
        private Timer timer;

        public RoulettePane() {
            addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    spin();
                }
            });
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            paintRoulette(g2d);
            g2d.dispose();
        }

        protected void spin() {
            if (timer != null && timer.isRunning()) {
                return;
            }
            timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    spinValue += 0.01;
                    repaint();
                }
            });
            timer.start();
        }

        protected void paintRoulette(Graphics2D g2d) {
            RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHints(hints);

            int width = getWidth();
            int height = getHeight();

            int dimeter = Math.min(width, height);

            AffineTransform at = AffineTransform.getRotateInstance(spinValue, dimeter / 2, dimeter / 2);
            g2d.transform(at);

            double angle = 360 / 36.9;
            double startAngle = 0;
            int color = 0;
            for (int i = 0; i < 37; i++) {
                if (i == 0) {
                    g2d.setColor(Color.GREEN);
                } else {
                    if (color == 0) {
                        g2d.setColor(Color.BLACK);
                        color = 1;
                    } else {
                        g2d.setColor(Color.RED);
                        color = 0;
                    }
                }

                g2d.fill(new Arc2D.Double(0, 0, dimeter, dimeter, startAngle, angle, Arc2D.PIE));
                startAngle += angle;
            }
        }
    }
}

nb: Я вывел перевод за то время, которое было раньше, поскольку я хотел сосредоточиться на том, чтобы сделать вывод более динамичным на основе фактической ширины / высоты компонента

...