Capovolgimento di rotazioni e immagini

Sto programmando un gioco platform in Java e sto codificando a mano le animazioni dei giocatori. Sto animando ciascun arto separatamente, cambiando la posizione e la rotazione. Funziona bene quando il giocatore è rivolto verso destra, ma quando il giocatore è rivolto a sinistra, non so come affrontare le rotazioni per farle sembrare uguali quando il giocatore gira a sinistra. La posizione di ciascuna parte del corpo è memorizzata rispetto ai valori xey del giocatore, quindi ho davvero bisogno di un modo per capovolgere le rotazioni orizzontalmente. So che non lo sto spiegando molto bene, ma se qualcuno capisce cosa sto cercando di dire e può aiutare, lo apprezzerei molto. Grazie in anticipo. 🙂

Quindi l’idea di base è semplicemente capovolgere / rispecchiare il contesto Graphics ridimensionando uno degli assi con un valore negativo ( -1 ).

Questo può essere realizzato semplicemente usando la Graphics#scale , per esempio, per capovolgere la grafica in orizzontale, si dovrebbe semplicemente utilizzare

 graphics.scale(-1, 1); 

Dovresti tradurre la Graphics base alla larghezza dell’area visualizzabile usando Graphics#translate per riposizionare l’immagine all’interno dell’area visualizzabile.

Tutto dipinge dopo questo sarà influenzato dal cambiamento. Per questo motivo dovresti scattare istantanee del contesto Graphics prima di ogni cambiamento significativo, ma assicurati di dispose quando hai finito …

Ecco un esempio (piuttosto patetico di animazione) … In sostanza, quando si preme le frecce sinistra o destra, viene capovolta una bandiera e la scena viene ridipinta. A seconda del flag, il contesto Graphics viene capovolto / specchiato …

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 actionPerformsd(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 actionPerformsd(ActionEvent e) { direction = 1; repaint(); } }); am.put("right", new AbstractAction() { @Override public void actionPerformsd(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); } } } 

La magia avviene in alcuni punti ...

Il contesto Graphics viene prima copiato e poi (se necessario) capovolto usando la 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); } 

Uso la stessa tecnica anche quando dipingo le gambe ...

 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(); } 

Questo isola le modifiche alla copia del contesto Graphics , ogni copia erediterà lo stato corrente del suo genitore, rendendo questa tecnica davvero utile ...