termodinamica sobrebalanceada rueda proyectos perpetuo movimiento maquinas con competencia boyle agua java keypress movement continuous

java - sobrebalanceada - Movimiento continuo con una sola pulsación de tecla?



rueda de movimiento perpetuo (2)

El concepto básico gira en torno a esta idea de un valor "delta" o "cambio". Este valor se aplica luego al estado que desea cambiar incrementando o disminuyendo el valor de estado.

Debido a la naturaleza de Swing, no puede bloquear el hilo de distribución de eventos, de lo contrario terminará impidiendo el procesamiento de eventos entrantes (como pintura y eventos clave).

Del mismo modo, nunca debe tratar de actualizar cualquier componente de la interfaz de usuario (o variable de estado que pueda afectar a la interfaz de usuario) desde cualquier hilo que no sea el EDT.

Si bien hay trucos que puede aplicar para facilitar estos requisitos, lo más simple es usar un javax.swing.Timer , que desencadena un evento actionPerformed de manera regular dentro del EDT.

Cuando esto ocurre, "actualiza" todos los elementos por la cantidad prescrita y vuelve a pintar la pantalla.

import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; 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 PacManTest { public static void main(String[] args) { new PacManTest(); } public PacManTest() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new MazePane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class PacMan { private int x; private int y; private int deltaX; private int deltaY; private BufferedImage sprite; public PacMan() { try { sprite = ImageIO.read(new File("PacMan.png")); } catch (IOException ex) { ex.printStackTrace(); } } public void move(int x, int y) { deltaX = x; deltaY = y; } public void update(MazePane pane) { x += deltaX; y += deltaY; if (x + sprite.getWidth() > pane.getWidth()) { x = pane.getWidth() - sprite.getWidth(); } else if (x < 0) { x = 0; } if (y + sprite.getHeight() > pane.getHeight()) { y = pane.getHeight() - sprite.getHeight(); } else if (y < 0) { y = 0; } } public void paint(MazePane pane, Graphics2D g2d) { Graphics2D g = (Graphics2D) g2d.create(); float angle = 0; if (deltaX != 0) { angle = deltaX > 0 ? 0 : 180; } else if (deltaY != 0) { angle = deltaY > 0 ? 90 : 270; } AffineTransform t = new AffineTransform(); t.translate(x, y); t.rotate(Math.toRadians(angle), sprite.getWidth() / 2, sprite.getHeight() / 2); g.setTransform(t); g.drawImage(sprite, 0, 0, pane); g.dispose(); } } public class MazePane extends JPanel { private PacMan pacMan; public MazePane() { pacMan = new PacMan(); Timer timer = new Timer(40, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { pacMan.update(MazePane.this); 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"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down"); am.put("left", new MoveAction(pacMan, -4, 0)); am.put("right", new MoveAction(pacMan, 4, 0)); am.put("up", new MoveAction(pacMan, 0, -4)); am.put("down", new MoveAction(pacMan, 0, 4)); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); pacMan.paint(this, g2d); g2d.dispose(); } public class MoveAction extends AbstractAction { private int deltaX; private int deltaY; private PacMan pacMan; public MoveAction(PacMan pacMan, int deltaX, int deltaY) { this.deltaX = deltaX; this.deltaY = deltaY; this.pacMan = pacMan; } @Override public void actionPerformed(ActionEvent e) { pacMan.move(deltaX, deltaY); } } } }

También te recomendaría que te tomes el tiempo para aprender sobre Key Bindings , KeyListener sufre de problemas de enfoque, que las ataduras de teclas son capaces de abordar ...

Estoy tratando de hacer un programa en Java que implique hacer que un objeto se mueva constantemente con solo presionar una tecla. Piensa en Pacman, donde presionas una vez y Pacman continúa subiendo hasta que presionas otra tecla. Quiero mantener el código simple si es posible. Mi movimiento original (una pulsación de tecla = un movimiento) es así:

public class AL extends KeyAdapter { public void keyPressed(KeyEvent e){ int keyCode = e.getKeyCode(); if(keyCode == e.VK_A){ x -= 5; } if(keyCode == e.VK_D){ x += 5; } if(keyCode == e.VK_W){ y -= 5; } if(keyCode == e.VK_S){ y += 5; } }

Los valores x e y en son la posición de un óvalo. Esto funciona a la perfección, pero quiero que siga moviéndose después de presionar la tecla solo una vez, en lugar de tener que sostenerlo para mantener el movimiento en marcha. Intenté un ciclo while con un parámetro booleano que se mueve mientras que es verdadero y no lo es mientras que es falso, pero tan pronto como activo el ciclo, congela el programa. Aquí hay un ejemplo de ese bit de código:

public void keyPressed(KeyEvent e){ int keyCode = e.getKeyCode(); if(keyCode == e.VK_LEFT && moveL==false){ moveL=true; moveR=false; moveU=false; moveD=false; while(moveL){ x--; } }

Por favor, ayúdame a resolver esto, he estado intentándolo y buscando por varios días. Agradezco cualquier ayuda que ustedes puedan dar. Gracias.


Necesita procesar el movimiento en un hilo separado. Es decir:

public class Pacman implements Runnable { public void run(){ //moving code, i.e. in a while loop //every move will notify the EDT: SwingUtilities.invokeLater(new Runnable(){ public void run(){ //update the Swing here - i.e. move Pacman } } } public void startMoving(){ new Thread(this).start(); } //more methods to set speed, direction, etc... }

Luego mantienes una referencia a una instancia de la clase Pacman en tu clase Gui y respondes a varias pulsaciones de teclas cambiando los parámetros de pacman:

public void keyPressed(KeyEvent e){ int keyCode = e.getKeyCode(); if(keyCode == e.VK_LEFT){ pacman.newDirection(LEFT); //for exmaple, enum with direction LEFT, RIGHT, UP, DOWN... } //etc... more logic }