Come spostare un’immagine durante l’ascolto di un tasto premuto in Java.

Sto iniziando a imparare la programmazione Java e penso che sia bello imparare java attraverso lo sviluppo del gioco. So come disegnare l’immagine e ascoltare un tasto premuto, quindi spostare quell’immagine. Ma è ansible far muovere l’immagine avanti e indietro verso la finestra mentre la finestra sta ascoltando un tasto? Come per esempio, mentre l’immagine o l’object (come l’astronave) si sposta da sinistra a destra nella finestra, quindi se premo il tasto spazio, un laser scatterà nella parte inferiore dello schermo (cool huh: D). Ma fondamentalmente voglio solo sapere come far muovere l’immagine da sinistra a destra mentre la finestra sta ascoltando un tasto premuto.

Sto pensando che aggiungerò un ascoltatore chiave alla mia finestra, quindi sparo un loop infinito per spostare l’immagine. O ho bisogno di conoscere il threading in modo che un altro thread sposterà l’object?

Si prega di avvisare.

Grazie molto.

Ma fondamentalmente voglio solo sapere come far muovere l’immagine da sinistra a destra mentre la finestra sta ascoltando un tasto premuto

Puoi utilizzare un timer di swing per animare un’immagine:

import java.awt.*; import java.awt.event.*; import javax.swing.*; public class TimerAnimation extends JLabel implements ActionListener { int deltaX = 2; int deltaY = 3; int directionX = 1; int directionY = 1; public TimerAnimation( int startX, int startY, int deltaX, int deltaY, int directionX, int directionY, int delay) { this.deltaX = deltaX; this.deltaY = deltaY; this.directionX = directionX; this.directionY = directionY; setIcon( new ImageIcon("dukewavered.gif") ); // setIcon( new ImageIcon("copy16.gif") ); setSize( getPreferredSize() ); setLocation(startX, startY); new javax.swing.Timer(delay, this).start(); } public void actionPerformsd(ActionEvent e) { Container parent = getParent(); // Determine next X position int nextX = getLocation().x + (deltaX * directionX); if (nextX < 0) { nextX = 0; directionX *= -1; } if ( nextX + getSize().width > parent.getSize().width) { nextX = parent.getSize().width - getSize().width; directionX *= -1; } // Determine next Y position int nextY = getLocation().y + (deltaY * directionY); if (nextY < 0) { nextY = 0; directionY *= -1; } if ( nextY + getSize().height > parent.getSize().height) { nextY = parent.getSize().height - getSize().height; directionY *= -1; } // Move the label setLocation(nextX, nextY); } public static void main(String[] args) { JPanel panel = new JPanel(); JFrame frame = new JFrame(); frame.setContentPane(panel); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); frame.getContentPane().setLayout(null); // frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) ); frame.getContentPane().add( new TimerAnimation(300, 100, 3, 2, -1, 1, 20) ); // frame.getContentPane().add( new TimerAnimation(0, 000, 5, 0, 1, 1, 20) ); frame.getContentPane().add( new TimerAnimation(0, 200, 5, 0, 1, 1, 80) ); frame.setSize(400, 400); frame.setLocationRelativeTo( null ); frame.setVisible(true); // frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) ); // frame.getContentPane().add( new TimerAnimation(10, 10, 3, 0, 1, 1, 10) ); } } 

È ansible aggiungere un KeyListener al pannello e funzionerà indipendentemente dall’animazione dell’immagine.

In alternativa a KeyListener , KeyListener considerazione l’utilizzo di azioni e associazioni di tasti , discusso qui . Derivato da questo esempio , il programma seguente sposta una linea verso sinistra, verso il basso, verso l’alto o verso destra usando i pulsanti oi tasti.

 import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; 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.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.KeyStroke; /** * @see https://stackoverflow.com/questions/6991648 * @see https://stackoverflow.com/questions/6887296 * @see https://stackoverflow.com/questions/5797965 */ public class LinePanel extends JPanel { private MouseHandler mouseHandler = new MouseHandler(); private Point p1 = new Point(100, 100); private Point p2 = new Point(540, 380); private boolean drawing; public LinePanel() { this.setPreferredSize(new Dimension(640, 480)); this.addMouseListener(mouseHandler); this.addMouseMotionListener(mouseHandler); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setColor(Color.blue); g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); g.drawLine(p1.x, p1.y, p2.x, p2.y); } private class MouseHandler extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { drawing = true; p1 = e.getPoint(); p2 = p1; repaint(); } @Override public void mouseReleased(MouseEvent e) { drawing = false; p2 = e.getPoint(); repaint(); } @Override public void mouseDragged(MouseEvent e) { if (drawing) { p2 = e.getPoint(); repaint(); } } } private class ControlPanel extends JPanel { private static final int DELTA = 10; public ControlPanel() { this.add(new MoveButton("\u2190", KeyEvent.VK_LEFT, -DELTA, 0)); this.add(new MoveButton("\u2191", KeyEvent.VK_UP, 0, -DELTA)); this.add(new MoveButton("\u2192", KeyEvent.VK_RIGHT, DELTA, 0)); this.add(new MoveButton("\u2193", KeyEvent.VK_DOWN, 0, DELTA)); } private class MoveButton extends JButton { KeyStroke k; int dx, dy; public MoveButton(String name, int code, final int dx, final int dy) { super(name); this.k = KeyStroke.getKeyStroke(code, 0); this.dx = dx; this.dy = dy; this.setAction(new AbstractAction(this.getText()) { @Override public void actionPerformsd(ActionEvent e) { LinePanel.this.p1.translate(dx, dy); LinePanel.this.p2.translate(dx, dy); LinePanel.this.repaint(); } }); ControlPanel.this.getInputMap( WHEN_IN_FOCUSED_WINDOW).put(k, k.toString()); ControlPanel.this.getActionMap().put(k.toString(), new AbstractAction() { @Override public void actionPerformsd(ActionEvent e) { MoveButton.this.doClick(); } }); } } } private void display() { JFrame f = new JFrame("LinePanel"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(this); f.add(new ControlPanel(), BorderLayout.SOUTH); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new LinePanel().display(); } }); } } 

Sì, un timer Swing e associazioni di tasti funzionerebbero bene. Ecco un altro esempio (il mio) 🙂

 import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.swing.*; public class AnimationWithKeyBinding { private static void createAndShowUI() { AnimationPanel panel = new AnimationPanel(); // the drawing JPanel JFrame frame = new JFrame("Animation With Key Binding"); frame.getContentPane().add(panel); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { createAndShowUI(); } }); } } @SuppressWarnings("serial") class AnimationPanel extends JPanel { public static final int SPRITE_WIDTH = 20; public static final int PANEL_WIDTH = 400; public static final int PANEL_HEIGHT = 400; private static final int MAX_MSTATE = 25; private static final int SPIN_TIMER_PERIOD = 16; private static final int SPRITE_STEP = 3; private int mState = 0; private int mX = (PANEL_WIDTH - SPRITE_WIDTH) / 2; private int mY = (PANEL_HEIGHT - SPRITE_WIDTH) / 2; private int oldMX = mX; private int oldMY = mY; private boolean moved = false; // an array of sprite images that are drawn sequentially private BufferedImage[] spriteImages = new BufferedImage[MAX_MSTATE]; public AnimationPanel() { // create and start the main animation timer new Timer(SPIN_TIMER_PERIOD, new SpinTimerListener()).start(); setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT)); setBackground(Color.white); createSprites(); // create the images setupKeyBinding(); } private void setupKeyBinding() { int condition = JComponent.WHEN_IN_FOCUSED_WINDOW; InputMap inMap = getInputMap(condition); ActionMap actMap = getActionMap(); // this uses an enum of Direction that holds ints for the arrow keys for (Direction direction : Direction.values()) { int key = direction.getKey(); String name = direction.name(); // add the key bindings for arrow key and shift-arrow key inMap.put(KeyStroke.getKeyStroke(key, 0), name); inMap.put(KeyStroke.getKeyStroke(key, InputEvent.SHIFT_DOWN_MASK), name); actMap.put(name, new MyKeyAction(this, direction)); } } // create a bunch of buffered images and place into an array, // to be displayed sequentially private void createSprites() { for (int i = 0; i < spriteImages.length; i++) { spriteImages[i] = new BufferedImage(SPRITE_WIDTH, SPRITE_WIDTH, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = spriteImages[i].createGraphics(); g2.setColor(Color.red); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); double theta = i * Math.PI / (2 * spriteImages.length); double x = SPRITE_WIDTH * Math.abs(Math.cos(theta)) / 2.0; double y = SPRITE_WIDTH * Math.abs(Math.sin(theta)) / 2.0; int x1 = (int) ((SPRITE_WIDTH / 2.0) - x); int y1 = (int) ((SPRITE_WIDTH / 2.0) - y); int x2 = (int) ((SPRITE_WIDTH / 2.0) + x); int y2 = (int) ((SPRITE_WIDTH / 2.0) + y); g2.drawLine(x1, y1, x2, y2); g2.drawLine(y1, x2, y2, x1); g2.dispose(); } } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.drawImage(spriteImages[mState], mX, mY, null); } public void incrementX(boolean right) { oldMX = mX; if (right) { mX = Math.min(getWidth() - SPRITE_WIDTH, mX + SPRITE_STEP); } else { mX = Math.max(0, mX - SPRITE_STEP); } moved = true; } public void incrementY(boolean down) { oldMY = mY; if (down) { mY = Math.min(getHeight() - SPRITE_WIDTH, mY + SPRITE_STEP); } else { mY = Math.max(0, mY - SPRITE_STEP); } moved = true; } public void tick() { mState = (mState + 1) % MAX_MSTATE; } private class SpinTimerListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { tick(); int delta = 20; int width = SPRITE_WIDTH + 2 * delta; int height = width; // make sure to erase the old image if (moved) { int x = oldMX - delta; int y = oldMY - delta; repaint(x, y, width, height); } int x = mX - delta; int y = mY - delta; // draw the new image repaint(x, y, width, height); moved = false; } } } enum Direction { UP(KeyEvent.VK_UP), DOWN(KeyEvent.VK_DOWN), LEFT(KeyEvent.VK_LEFT), RIGHT(KeyEvent.VK_RIGHT); private int key; private Direction(int key) { this.key = key; } public int getKey() { return key; } } // Actions for the key binding @SuppressWarnings("serial") class MyKeyAction extends AbstractAction { private AnimationPanel draw; private Direction direction; public MyKeyAction(AnimationPanel draw, Direction direction) { this.draw = draw; this.direction = direction; } @Override public void actionPerformed(ActionEvent e) { switch (direction) { case UP: draw.incrementY(false); break; case DOWN: draw.incrementY(true); break; case LEFT: draw.incrementX(false); break; case RIGHT: draw.incrementX(true); break; default: break; } } } 



Ecco un altro esempio che utilizza questo foglio sprite:

inserisci la descrizione dell'immagine qui

ottenuto da questo sito .

Anche in questo caso si tratta di un esempio di disegno all'interno del metodo paintComponent di JPanel e l'uso di associazioni di tasti per indicare quale direzione spostare.

 import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.event.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; import java.util.Map; import javax.imageio.ImageIO; import javax.swing.*; @SuppressWarnings("serial") public class Mcve3 extends JPanel { private static final int PREF_W = 800; private static final int PREF_H = 640; private static final int TIMER_DELAY = 50; private int spriteX = 400; private int spriteY = 320; private SpriteDirection spriteDirection = SpriteDirection.RIGHT; private MySprite sprite = null; private Timer timer = null; public Mcve3() { try { sprite = new MySprite(spriteDirection, spriteX, spriteY); } catch (IOException e) { e.printStackTrace(); System.exit(-1); } setBackground(Color.WHITE); setKeyBindings(SpriteDirection.LEFT, KeyEvent.VK_LEFT); setKeyBindings(SpriteDirection.RIGHT, KeyEvent.VK_RIGHT); setKeyBindings(SpriteDirection.FORWARD, KeyEvent.VK_DOWN); setKeyBindings(SpriteDirection.AWAY, KeyEvent.VK_UP); timer = new Timer(TIMER_DELAY, new TimerListener()); timer.start(); } private void setKeyBindings(SpriteDirection dir, int keyCode) { int condition = WHEN_IN_FOCUSED_WINDOW; InputMap inputMap = getInputMap(condition); ActionMap actionMap = getActionMap(); KeyStroke keyPressed = KeyStroke.getKeyStroke(keyCode, 0, false); KeyStroke keyReleased = KeyStroke.getKeyStroke(keyCode, 0, true); inputMap.put(keyPressed, keyPressed.toString()); inputMap.put(keyReleased, keyReleased.toString()); actionMap.put(keyPressed.toString(), new MoveAction(dir, false)); actionMap.put(keyReleased.toString(), new MoveAction(dir, true)); } @Override public Dimension getPreferredSize() { if (isPreferredSizeSet()) { return super.getPreferredSize(); } return new Dimension(PREF_W, PREF_H); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); sprite.draw(g); } private class MoveAction extends AbstractAction { private SpriteDirection dir; private boolean released; public MoveAction(SpriteDirection dir, boolean released) { this.dir = dir; this.released = released; } @Override public void actionPerformsd(ActionEvent e) { if (released) { sprite.setMoving(false); } else { sprite.setMoving(true); sprite.setDirection(dir); } } } private class TimerListener implements ActionListener { @Override public void actionPerformsd(ActionEvent e) { if (sprite.isMoving()) { sprite.tick(); } repaint(); } } private static void createAndShowGui() { Mcve3 mainPanel = new Mcve3(); JFrame frame = new JFrame("MCVE"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(mainPanel); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> createAndShowGui()); } } 

 class MySprite { private static final String SPRITE_SHEET_PATH = "http://" + "orig12.deviantart.net/7db3/f/2010/338/3/3/" + "animated_sprite_sheet_32x32_by_digibody-d3479l2.gif"; private static final int MAX_MOVING_INDEX = 4; private static final int DELTA = 4; private SpriteDirection direction; private Map standingImgMap = new EnumMap<>(SpriteDirection.class); private Map> movingImgMap = new EnumMap<>(SpriteDirection.class); private int x; private int y; private boolean moving = false; private int movingIndex = 0; public MySprite(SpriteDirection direction, int x, int y) throws IOException { this.direction = direction; this.x = x; this.y = y; createSprites(); } public void draw(Graphics g) { Image img = null; if (!moving) { img = standingImgMap.get(direction); } else { img = movingImgMap.get(direction).get(movingIndex); } g.drawImage(img, x, y, null); } private void createSprites() throws IOException { URL spriteSheetUrl = new URL(SPRITE_SHEET_PATH); BufferedImage img = ImageIO.read(spriteSheetUrl); // get sub-images (sprites) from the sprite sheet // magic numbers for getting sprites from sheet, all obtained by trial and error int x0 = 0; int y0 = 64; int rW = 32; int rH = 32; for (int row = 0; row < 4; row++) { SpriteDirection dir = SpriteDirection.values()[row]; List imgList = new ArrayList<>(); movingImgMap.put(dir, imgList); int rY = y0 + row * rH; for (int col = 0; col < 5; col++) { int rX = x0 + col * rW; BufferedImage subImg = img.getSubimage(rX, rY, rW, rH); if (col == 0) { // first image is standing standingImgMap.put(dir, subImg); } else { // all others are moving imgList.add(subImg); } } } } public SpriteDirection getDirection() { return direction; } public void setDirection(SpriteDirection direction) { if (this.direction != direction) { setMoving(false); } this.direction = direction; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public boolean isMoving() { return moving; } public void setMoving(boolean moving) { this.moving = moving; if (!moving) { movingIndex = 0; } } public void tick() { if (moving) { switch (direction) { case RIGHT: x += DELTA; break; case LEFT: x -= DELTA; break; case FORWARD: y += DELTA; break; case AWAY: y -= DELTA; } movingIndex++; movingIndex %= MAX_MOVING_INDEX; } } public int getMovingIndex() { return movingIndex; } public void setMovingIndex(int movingIndex) { this.movingIndex = movingIndex; } } 

 enum SpriteDirection { FORWARD, LEFT, AWAY, RIGHT }