0

Yes, i do know you can use AffineTransformation, however i want my sword image to rotate around a character that i have made (black block drawn in graphics) 360 degrees visibly instead of just one rotation. Basically i want a rotation system like that of Terraria. I know how to get the x and y of the character so the question is: How do i make it rotate around a point that i define? my code is set up like this

    f.addMouseListener(new MouseAdapter(){
    public void mouseClicked(MouseEvent e){
        swordSwinging=true;
    }
});

...

if(swordSwinging){
    //swinging code goes here
}

repaint();
BaconMan97
  • 67
  • 1
  • 9

2 Answers2

6

You mean something like...

enter image description here

(Please note, the red line is a guide line to indicate the angle from the center, you won't need it ;))

The fancy, pancy stuff is in the getSwordHandlePoint method, which calculates the point along the vector at which the handle should be placed...

public class TestSword {

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

    public TestSword() {
        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) {
                }

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

    public class SwordPane extends JPanel {

        private BufferedImage character;
        private BufferedImage sword;
        private double angle = 0;

        public SwordPane() {
            try {
                character = ImageIO.read(new File("character.png"));
                sword = ImageIO.read(new File("Sword.png"));
            } catch (IOException exp) {
                exp.printStackTrace();
            }

            Timer timer = new Timer(100, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    angle += 10;
                    if (angle > 360) {
                        angle -= 360;
                    }
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();

        }

        @Override
        public Dimension getPreferredSize() {
            int width = character.getHeight() + sword.getWidth();
            int height = character.getHeight() + sword.getWidth();

            return new Dimension(width * 2, height * 2);
        }

        protected Point getSwordHandlePoint() {

            int radius = 272; // This is the height of the character...

            int x = Math.round(getWidth() / 2);
            int y = Math.round(getHeight() / 2);

            double rads = Math.toRadians(angle - 180); // Make 0 point out to the right...
            // If you add sword.getWidth, you might be able to change the above...
            int fullLength = Math.round((radius / 2f)) - sword.getWidth();

            // Calculate the outter point of the line
            int xPosy = Math.round((float) (x + Math.cos(rads) * fullLength));
            int yPosy = Math.round((float) (y - Math.sin(rads) * fullLength));

            return new Point(xPosy, yPosy);

        }

        @Override
        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();

            int x = (getWidth() - character.getWidth()) / 2;
            int y = (getHeight() - character.getHeight()) / 2;

            g2d.drawImage(character, x, y, this);

            x = getWidth() / 2;
            y = getHeight() / 2;

            Point p = getSwordHandlePoint();
            g2d.setColor(Color.RED);
            g2d.drawLine(x, y, p.x, p.y);

            AffineTransform at = AffineTransform.getTranslateInstance(p.x, p.y);
            at.rotate(Math.toRadians(-angle));
            g2d.setTransform(at);
            g2d.drawImage(sword, 0, 0, this);

            g2d.dispose();

        }
    }
}

Now, my trig is hopeless, less then hopeless. I "borrowed" the algorithm off the net and tweaked for my own needs...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • You must embrace radians, for [example](http://stackoverflow.com/a/3256941/230513). Your daughter will be asking for help with homework surprisingly soon. :-) – trashgod Oct 19 '12 at 18:17
  • Thank you for the thourough response! The diagram really helped as well! I will try this code now! – BaconMan97 Oct 20 '12 at 17:56
  • Hey i tried the code out and modified it to fit my settings, however im getting an error on the timer code. I guess it wont accept a new ActionListener in the timer or accept any of this code timer.setRepeats(true); timer.setCoalesce(true); timer.start(); – BaconMan97 Oct 20 '12 at 19:16
  • http://s10.postimage.org/h7xj6d4nd/Error.png "The constructor Timer(int, new ActionListener(){}) is undefined" also "The method setRepeats(boolean) is undefined for the type Timer" and such for the methods that you listed – BaconMan97 Oct 20 '12 at 19:31
  • It sounds like you're use `java.util.Timer` instead of `javax.swing.Timer` – MadProgrammer Oct 20 '12 at 19:39
  • Oh! Thanks! That fixed the method errors. But it still doesnt want me to add an action listener – BaconMan97 Oct 20 '12 at 19:46
  • Make sure you've imported the `ActionListener` – MadProgrammer Oct 20 '12 at 19:57
  • Ah, fixed it thanks for that! Sorry about all the questions, im done now :P – BaconMan97 Oct 20 '12 at 20:04
  • @MadProgrammer this also uses `rotate(...)`, heh. – Mordechai Oct 21 '12 at 07:37
  • @M.M. Yes, it use affine transformation to rotate and position the sword, but what it does do is makes the sword orbit the player, which is far beyond just what rotate does, besides the OP already stated that they know how to apply a affine transformation – MadProgrammer Oct 21 '12 at 08:10
1

The Graphics2D class, has a method g2.rotate(...), call a for loop setting the rotate at one degree more, at a time, then invoke g2.drawImage(...), in the loop, after the each change (if it's in the paintComponent() method, and the loop is outside - call repaint() in the for loop).

Mordechai
  • 15,437
  • 2
  • 41
  • 82