ich ursprünglich eine Antwort über Key Bindings hatte, aber nach einer kleinen Prüfung fand ich, dass sie hatten immer noch die gleiche Stottern Problem.
Verlassen Sie sich nicht auf die Wiederholungsrate des Betriebssystems. Es kann für jede Plattform anders sein und ein Benutzer kann sie auch anpassen.
Verwenden Sie stattdessen einen Timer, um das Ereignis zu planen. Sie starten den Timer auf einem keyPressed und stoppen den Timer on keyReleased.
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.Map;
import java.util.HashMap;
import javax.imageio.ImageIO;
import javax.swing.*;
public class KeyboardAnimation implements ActionListener
{
private final static String PRESSED = "pressed ";
private final static String RELEASED = "released ";
private final static Point RELEASED_POINT = new Point(0, 0);
private JComponent component;
private Timer timer;
private Map<String, Point> pressedKeys = new HashMap<String, Point>();
public KeyboardAnimation(JComponent component, int delay)
{
this.component = component;
timer = new Timer(delay, this);
timer.setInitialDelay(0);
}
public void addAction(String keyStroke, int deltaX, int deltaY)
{
// InputMap inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
InputMap inputMap = component.getInputMap();
ActionMap actionMap = component.getActionMap();
String pressedKey = PRESSED + keyStroke;
KeyStroke pressedKeyStroke = KeyStroke.getKeyStroke(pressedKey);
Action pressedAction = new AnimationAction(keyStroke, new Point(deltaX, deltaY));
inputMap.put(pressedKeyStroke, pressedKey);
actionMap.put(pressedKey, pressedAction);
String releasedKey = RELEASED + keyStroke;
KeyStroke releasedKeyStroke = KeyStroke.getKeyStroke(releasedKey);
Action releasedAction = new AnimationAction(keyStroke, RELEASED_POINT);
inputMap.put(releasedKeyStroke, releasedKey);
actionMap.put(releasedKey, releasedAction);
}
private void handleKeyEvent(String keyStroke, Point moveDelta)
{
// Keep track of which keys are pressed
if (RELEASED_POINT == moveDelta)
pressedKeys.remove(keyStroke);
else
pressedKeys.put(keyStroke, moveDelta);
// Start the Timer when the first key is pressed
if (pressedKeys.size() == 1)
{
timer.start();
}
// Stop the Timer when all keys have been released
if (pressedKeys.size() == 0)
{
timer.stop();
}
}
// Invoked when the Timer fires
public void actionPerformed(ActionEvent e)
{
moveComponent();
}
// Move the component to its new location
private void moveComponent()
{
int componentWidth = component.getSize().width;
int componentHeight = component.getSize().height;
Dimension parentSize = component.getParent().getSize();
int parentWidth = parentSize.width;
int parentHeight = parentSize.height;
// Calculate new move
int deltaX = 0;
int deltaY = 0;
for (Point delta : pressedKeys.values())
{
deltaX += delta.x;
deltaY += delta.y;
}
// Determine next X position
int nextX = Math.max(component.getLocation().x + deltaX, 0);
if (nextX + componentWidth > parentWidth)
{
nextX = parentWidth - componentWidth;
}
// Determine next Y position
int nextY = Math.max(component.getLocation().y + deltaY, 0);
if (nextY + componentHeight > parentHeight)
{
nextY = parentHeight - componentHeight;
}
// Move the component
component.setLocation(nextX, nextY);
}
private class AnimationAction extends AbstractAction implements ActionListener
{
private Point moveDelta;
public AnimationAction(String keyStroke, Point moveDelta)
{
super(PRESSED + keyStroke);
putValue(ACTION_COMMAND_KEY, keyStroke);
this.moveDelta = moveDelta;
}
public void actionPerformed(ActionEvent e)
{
handleKeyEvent((String)getValue(ACTION_COMMAND_KEY), moveDelta);
}
}
public static void main(String[] args)
{
JPanel contentPane = new JPanel();
contentPane.setLayout(null);
Icon dukeIcon = null;
try
{
dukeIcon = new ImageIcon("dukewavered.gif");
// dukeIcon = new ImageIcon(ImageIO.read(new URL("http://duke.kenai.com/iconSized/duke4.gif")));
}
catch(Exception e)
{
System.out.println(e);
}
JLabel duke = new JLabel(dukeIcon);
duke.setSize(duke.getPreferredSize());
duke.setLocation(100, 100);
contentPane.add(duke);
KeyboardAnimation navigation = new KeyboardAnimation(duke, 24);
navigation.addAction("LEFT", -3, 0);
navigation.addAction("RIGHT", 3, 0);
navigation.addAction("UP", 0, -3);
navigation.addAction("DOWN", 0, 3);
navigation.addAction("A", -5, 0);
navigation.addAction("S", 5, 0);
navigation.addAction("Z", 0, -5);
navigation.addAction("X", 0, 5);
navigation.addAction("V", 5, 5);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.getContentPane().add(new JTextField(), BorderLayout.SOUTH);
frame.getContentPane().add(contentPane);
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Dieser Code wurde unter Windows getestet, wo die Reihenfolge der Ereignisse keyPressed ist, keyPressed, keyPressed ... keyReleased.
Aber ich denke, auf einem Mac (oder Unix) die Reihenfolge der Ereignisse ist keyPressed, keyReleased, keyPressed, keyReleased ... Also ich bin nicht sicher, ob dieser Code würde funktioniert besser als Ihre aktuellen Code.
Ich hatte ursprünglich eine Antwort auf Key Bindings, aber nach ein paar Tests fand ich, dass sie immer noch das gleiche Stottern Problem hatten. +1 für das andere Zeug jedoch. – syb0rg
@ syb0rg Deshalb brauchen Sie diese kleine Fahne;). Das letzte Beispiel zeigt eine nette Idee, einem Schlüsselereignis zu erlauben, ein Beschleunigungsdelta anzuwenden, je länger es gedrückt wird, je mehr das Delta erhöht wird, bis es freigegeben wird und das Delta umgekehrt wird, verlangsamt sich das Objekt im Laufe der Zeit;) – MadProgrammer
@ syb0rg Hinzugefügt ein einfaches Beispiel, um das Prinzip zu demonstrieren;) – MadProgrammer