Отражающие вращения и изображения

Я программирую платформенную игру на Java, и я вручную кодирую анимацию игрока. Я одурачиваю каждую конечность отдельно, изменяя положение и rotation. Это отлично работает, когда игрок смотрит вправо, но когда игрок смотрит влево, я не знаю, как обращаться с поворотами, чтобы они выглядели одинаково, когда игрок поворачивает налево. Каждое расположение части тела сохраняется относительно значений x и y игрока, поэтому мне действительно нужен способ поворота поворотов по горизонтали. Я знаю, что я не очень хорошо объясняю это, но если кто-то поймет, что я пытаюсь сказать и могу помочь, я бы очень признателен. Заранее спасибо. 🙂

    Таким образом, основная идея состоит в том, чтобы просто перевернуть / зеркально отразить контекст Graphics , масштабируя одну из осей на отрицательное значение ( -1 ).

    Это можно сделать, просто используя Graphics#scale , например, чтобы перевернуть графику по горизонтали, вы просто использовали бы

     graphics.scale(-1, 1); 

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

    Эти изменения повлияют на все, что нарисовано после этого. Из-за этого вы должны делать снимки контекста Graphics перед каждым существенным изменением, просто убедитесь, что вы dispose от него, когда закончите …

    Вот пример (довольно трогательный анимационный мудрый) … В основном, когда вы нажимаете стрелки влево или вправо, флаг переворачивается, а сцена перекрашивается. В зависимости от флага контекст Graphics перевернулся / зеркалирован …

    Pony Run

     import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class AnimateCharacter { public static void main(String[] args) { new AnimateCharacter(); } public AnimateCharacter() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private BufferedImage body; private BufferedImage[] legs; private double[] angels; private double[] deltas; private Point[] pivots = new Point[]{ // Foreground... new Point(100, 227), // Foreleg new Point(155, 201), // Hindleg // Background... new Point(93, 218), // Foreleg new Point(143, 195), // Hindleg }; private Point[] locations = new Point[]{ // Foreground... new Point(67, 221), // Foreleg new Point(124, 172), // Hindleg // Background... new Point(60, 219), // Foreleg new Point(112, 166), // Hindleg }; private int direction = 1; public TestPane() { legs = new BufferedImage[4]; angels = new double[]{ 45, 40, -5, 0 }; deltas = new double[]{ -4, -4, 4, 4 }; try { body = ImageIO.read(getClass().getResource("/Body.png")); // Foreground... legs[0] = ImageIO.read(getClass().getResource("/ForeLeg.png")); legs[1] = ImageIO.read(getClass().getResource("/HindLeg.png")); // Background... legs[2] = ImageIO.read(getClass().getResource("/ForeLeg.png")); legs[3] = ImageIO.read(getClass().getResource("/HindLeg.png")); } catch (IOException exp) { exp.printStackTrace(); } Timer timer = new Timer(40, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { for (int index = 0; index < angels.length; index++) { angels[index] += deltas[index]; if (angels[index] < -45) { angels[index] = -45; deltas[index] *= -1; } else if (angels[index] > 45) { angels[index] = 45; deltas[index] *= -1; } } repaint(); } }); timer.start(); InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW); ActionMap am = getActionMap(); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right"); am.put("left", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { direction = 1; repaint(); } }); am.put("right", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { direction = -1; repaint(); } }); } @Override public Dimension getPreferredSize() { return body == null ? new Dimension(200, 200) : new Dimension(body.getWidth() + 50, body.getHeight() + 50); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); applyQualityRenderingHints(g2d); int x = (getWidth() - body.getWidth()) / 2; int y = (getHeight() - body.getHeight()) / 2; if (direction < 0) { g2d.scale(-1, 1); g2d.translate(-getWidth(), 0); } // Background legs... drawLegs(g2d, x, y, 2); g2d.drawImage(body, x, y, this); // Foreground legs... drawLegs(g2d, x, y, 0); g2d.dispose(); } protected void drawLegs(Graphics2D g2d, int x, int y, int offset) { for (int index = 0; index < 2; index++) { Graphics2D copy = (Graphics2D) g2d.create(); copy.translate(x, y); int leg = index + offset; int pivotX = pivots[leg].x; int pivotY = pivots[leg].y; copy.rotate(Math.toRadians(angels[leg]), pivotX, pivotY); copy.drawImage( legs[leg], locations[leg].x, locations[leg].y, this); copy.dispose(); } } public void applyQualityRenderingHints(Graphics2D g2d) { g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); // g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); } } } 

    Магия происходит в нескольких местах ...

    Контекст Graphics сначала копируется, а затем (при необходимости) переворачивается с использованием scale ...

     protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); //... if (direction < 0) { g2d.scale(-1, 1); g2d.translate(-getWidth(), 0); } 

    Я также использую ту же технику, когда рисую ноги ...

     protected void drawLegs(Graphics2D g2d, int x, int y, int offset) { for (int index = 0; index < 2; index++) { Graphics2D copy = (Graphics2D) g2d.create(); copy.translate(x, y); //... copy.rotate(Math.toRadians(angels[leg]), pivotX, pivotY); copy.drawImage( legs[leg], locations[leg].x, locations[leg].y, this); copy.dispose(); } 

    Это изолирует изменения в копии контекста Graphics , каждая копия наследует текущее состояние его родителя, делая это действительно полезным методом ...

    Interesting Posts

    Что такое восстановление системы в операционных системах Windows?

    Как найти драйверы, нарушающие применение цифровой подписи в Windows 7 64bit

    Вызов внешней функции classа из внутреннего classа

    Должен ли я отформатировать USB-накопители и SD-карты в FAT, FAT32, exFAT или NTFS? (Файлы Windows, живые Linux-искатели)

    Разрешить Java использовать ненадежный сертификат для соединения SSL / HTTPS

    objective камеры не работать с Samsung Galaxy S3

    Включить или импортировать веб-шрифты Google Web Fonts?

    Бросок или попытка + улов

    Мощность здоровья HDD на счет / часы

    Могу ли я создать резервную копию виртуальной машины виртуальной машины?

    Звук отключается, когда загрузка ЦП выше ~ 30%

    Могу ли я изменить поведение ярлыка firefox на панели задач Windows 7?

    Использование atan2 для нахождения угла между двумя векторами

    Ленивая загрузка содержимого вкладки WPF

    Как перезагрузить компьютеры в локальной сети, зная только внешний IP-адрес?

    Давайте будем гением компьютера.