问题描述
我有一个具体的问题有一场比赛,我创建的类。
本场比赛是打破它的实现。要移动在底部我只是用一个关键的侦听器平台。问题是,在第一密钥preSS之后有一个短暂的滞后或口吃平台开始移动之前。我怎么能prevent这得到平滑的响应?有另一种方式比KeyListener的?键绑定?
下面是关键监听器实现
私有类KeyControl实现的KeyListener { 私人INT DX = 20; 公共无效键pressed(KeyEvent的E){
如果(e.getKey code()== KeyEvent.VK_RIGHT){
如果(DX℃,)
DX = -dx;
gamePanel.movePlatform(DX);
} 如果(e.getKey code()== KeyEvent.VK_LEFT){
如果(DX大于0)
DX = -dx;
gamePanel.movePlatform(DX);
} 如果(e.getKey code()== KeyEvent.VK_SPACE){
的System.out.println(空间);
gamePanel.play();
} 如果(e.getKey code()== KeyEvent.VK_ESCAPE){
gamePanel.pause();
} }
}
和这里是移动平台周围
方法 公共无效movePlatform(INT DX){
INT nextDX = DX; 如果(暂停|| INIT){
DX = 0;
} //确保平台犯规超过右边框
如果(platform.getX()+ platform.getWidth()+ DX> size.getWidth()){
如果(nextDX℃,)
DX = nextDX;
其他
DX = 0;
} //确保平台犯规超过左边框
如果(platform.getX()+ DX&下; = 0){
如果(nextDX大于0)
DX = nextDX;
其他
DX = 0;
} platform.setFrame(platform.getX()+ DX,platform.getY(),platform.getWidth(),platform.getHeight());
platformIntervalX =新间隔((int)的platform.getX(),(INT)(platform.getX()+ platform.getWidth()));
platformIntervalY =新间隔((int)的(platform.getY() - platform.getHeight()),(INT)platform.getY());
重绘();
}
解决的办法是不使用的KeyListener的主要preSS移动你的精灵。关键是不依赖于特定的硬件键preSS频率,使用一个Swing计时器来创建自己的频率。而是使用按键绑定和Swing的计时器。启动重点preSS的时间和停止它的键释放。
例如,运行此code和preSS并释放向上箭头键:
进口java.awt.Color中;
进口java.awt.Dimension中;
进口java.awt.Font中;
进口java.awt.event.ActionEvent中;
进口java.awt.event.ActionListener;
进口java.awt.event.KeyEvent中;进口的javax.swing *。@燮pressWarnings(串行)
公共类KeyBindingEg继承JPanel {
私有静态最后弦乐UP_KEY_ preSSED =向上键pressed
私有静态最后弦乐UP_KEY_RELEASED =向上键发布了;
私有静态最终诠释UP_TIMER_DELAY = 50;
私有静态最终颜色FLASH_COLOR = Color.red; 私人定时器upTimer;
私人标签的JLabel =新的JLabel(); 公共KeyBindingEg(){
label.setFont(label.getFont()的deriveFont(Font.BOLD,32));
label.setOpaque(真);
添加(标签); 集preferredSize(新尺寸(400,300)); INT条件= WHEN_IN_FOCUSED_WINDOW;
InputMap中的InputMap = getInputMap中(条件);
ActionMap中的ActionMap = getActionMap();
的KeyStroke upKey pressed = KeyStroke.getKeyStroke(KeyEvent.VK_UP,0,FALSE);
的KeyStroke upKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_UP,0,真正的); inputMap.put(upKey pressed,UP_KEY_ preSSED);
inputMap.put(upKeyReleased,UP_KEY_RELEASED); actionMap.put(UP_KEY_ preSSED,新UpAction(假));
actionMap.put(UP_KEY_RELEASED,新UpAction(真)); } 私有类UpAction扩展AbstractAction {
私人布尔onKeyRelease; 公共UpAction(布尔onKeyRelease){
this.onKeyRelease = onKeyRelease;
} @覆盖
公共无效的actionPerformed(ActionEvent的EVT){
如果(!onKeyRelease){
如果(upTimer =空&放大器;!&放大器; upTimer.isRunning()){
返回;
}
的System.out.println(键pressed);
label.setText(UP_KEY_ preSSED); upTimer =新的Timer(UP_TIMER_DELAY,新的ActionListener(){ @覆盖
公共无效的actionPerformed(ActionEvent的五){
颜色C = label.getBackground();
如果(FLASH_COLOR.equals(c))的{
label.setBackground(NULL);
label.setForeground(Color.black);
}其他{
label.setBackground(FLASH_COLOR);
label.setForeground(Color.white);
}
}
});
upTimer.start();
}其他{
的System.out.println(键释放);
如果(upTimer =空&放大器;!&放大器; upTimer.isRunning()){
upTimer.stop();
upTimer = NULL;
}
label.setText();
}
} } 私有静态无效createAndShowGui(){
KeyBindingEg的mainPanel =新KeyBindingEg(); JFrame的帧=新的JFrame(KeyBindingEg);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane()加(mainPanel中)。
frame.pack();
frame.setLocationByPlatform(真);
frame.setVisible(真);
} 公共静态无效的主要(字串[] args){
SwingUtilities.invokeLater(Runnable的新(){
公共无效的run(){
createAndShowGui();
}
});
}
}
修改
或者一个更好的例子,一个基于方向键中的一个关键preSS任何方向移动的精灵。无延迟遇到:
进口java.awt.Color中;
进口java.awt.Dimension中;
进口java.awt.Graphics;
进口java.awt.event.ActionEvent中;
进口java.awt.event.ActionListener;
进口java.awt.event.KeyEvent中;
进口java.awt.image.BufferedImage中;
进口java.util.EnumMap中;
进口的java.util.Map;进口的javax.swing *。@燮pressWarnings(串行)
公共类KeyBindingEg2继承JPanel {
枚举目录{
LEFT(左,KeyEvent.VK_LEFT,-1,0),
RIGHT(右,KeyEvent.VK_RIGHT,1,0),
向上(向上,KeyEvent.VK_UP,0,-1),
DOWN(向下,KeyEvent.VK_DOWN,0,1); 私人字符串名称;
私人诠释键code;
私人诠释DELTAX;
私人诠释DELTAY;
私人目录(字符串名称,诠释关键code,INT DELTAX,诠释DELTAY){
this.name =名称;
this.key code =键code;
this.deltaX = DELTAX;
this.deltaY = DELTAY;
}
公共字符串的getName(){
返回名称;
}
公众诠释getKey code(){
返回键code;
}
公众诠释getDeltaX(){
返回DELTAX;
}
公众诠释getDeltaY(){
返回DELTAY;
}
}
公共静态最终诠释TIMER_DELAY = 10;
公共静态最终诠释DELTA_X = 2;
公共静态最终诠释DELTA_Y = DELTA_X;
公共静态最终诠释SPRITE_WIDTH = 10;
公共静态最终诠释SPRITE_HEIGHT = SPRITE_WIDTH;
私有静态最后弦乐preSSED =pressed
RELEASED =私有静态最后弦乐释放;
私有静态最终诠释preF_W = 800;
私有静态最终诠释preF_H = 650;
私人地图<迪尔,布尔> dirMap =新的EnumMap的<>(Dir.class);
私人INT spriteX = 0;
私人INT spriteY = 0;
私人的BufferedImage精灵;
私人定时器animationTimer =新的Timer(TIMER_DELAY,新AnimationListener()); 公共KeyBindingEg2(){
对于(导演导演:Dir.values()){
dirMap.put(DIR,Boolean.FALSE);
}
精灵= createSprite();
setKeyBindings();
animationTimer.start();
} 私人的BufferedImage createSprite(){
BufferedImage的SPRT =新的BufferedImage(SPRITE_WIDTH,SPRITE_HEIGHT,BufferedImage.TYPE_INT_ARGB);
图形G = sprt.getGraphics();
g.setColor(Color.RED);
g.fillRect(0,0,SPRITE_WIDTH,SPRITE_HEIGHT);
g.dispose();
返回SPRT;
} @覆盖
公共尺寸的get preferredSize(){
返回新的Dimension(preF_W,preF_H);
} @覆盖
保护无效paintComponent(图形G){
super.paintComponent方法(G);
如果(精灵!= NULL){
g.drawImage(雪碧,spriteX,spriteY,这一点);
}
} 私人无效setKeyBindings(){
INT条件= WHEN_IN_FOCUSED_WINDOW;
InputMap中的InputMap = getInputMap中(条件);
ActionMap中的ActionMap = getActionMap(); 对于(导演导演:Dir.values()){
关键的KeyStroke pressed = KeyStroke.getKeyStroke(dir.getKey code(),0,FALSE);
的KeyStroke的keyReleased = KeyStroke.getKeyStroke(dir.getKey code(),0,真正的); inputMap.put(键pressed,dir.toString()+ preSSED);
inputMap.put(的keyReleased,dir.toString()+释放); actionMap.put(dir.toString()+ preSSED,新DirAction(DIR,preSSED));
actionMap.put(dir.toString()+发布新DirAction(DIR发布));
} } 私有类AnimationListener实现的ActionListener {
@覆盖
公共无效的actionPerformed(ActionEvent的五){
INT下一页末= spriteX;
INT newy指定= spriteY;
对于(导演导演:Dir.values()){
如果(dirMap.get(DIR)){
下一页末+ = dir.getDeltaX()* DELTA_X;
newy指定+ = dir.getDeltaY()* DELTA_Y;
}
}
如果(下一页末℃,|| newy指定℃,){
返回;
}
如果(下一页末+ SPRITE_WIDTH>的getWidth()|| newy指定+ SPRITE_HEIGHT>的getHeight()){
返回;
}
spriteX =下一页末;
spriteY = newy指定;
重绘();
}
} 私有类DirAction扩展AbstractAction { 私人字符串pressedOrReleased;
私人目录目录; 公共DirAction(迪尔目录,字符串pressedOrReleased){
this.dir = DIR;
这pressedOrReleased = pressedOrReleased。
} @覆盖
公共无效的actionPerformed(ActionEvent的EVT){
如果(pressedOrReleased.equals(preSSED)){
dirMap.put(DIR,Boolean.TRUE);
}否则如果(pressedOrReleased.equals(释放)){
dirMap.put(DIR,Boolean.FALSE);
}
} } 私有静态无效createAndShowGui(){
KeyBindingEg2的mainPanel =新KeyBindingEg2(); JFrame的帧=新的JFrame(KeyBindingEg);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane()加(mainPanel中)。
frame.pack();
frame.setLocationByPlatform(真);
frame.setVisible(真);
} 公共静态无效的主要(字串[] args){
SwingUtilities.invokeLater(Runnable的新(){
公共无效的run(){
createAndShowGui();
}
});
}
}
I have a specific "problem" with a game I'm creating for class.
The game is an implementation of "Break it". To move the platform at the bottom I just used a key listener. The problem is that after the first key press there is a short "lag" or "stutter" before the platform starts moving. How could I prevent this to get a smooth response? Is there another way than KeyListener? KeyBindings?
Here is the key listener implementation
private class KeyControl implements KeyListener {
private int dx = 20;
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
if(dx < 0 )
dx = -dx;
gamePanel.movePlatform(dx);
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
if(dx > 0 )
dx = -dx;
gamePanel.movePlatform(dx);
}
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
System.out.println("space");
gamePanel.play();
}
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
gamePanel.pause();
}
}
}
and here is the method that moves the platform around
public void movePlatform(int dx) {
int nextDX = dx;
if(paused || init) {
dx = 0;
}
// make sure platform doesnt exceed right border
if(platform.getX() + platform.getWidth() + dx> size.getWidth()) {
if(nextDX < 0)
dx = nextDX;
else
dx = 0;
}
// make sure platform doesnt exceed left border
if(platform.getX() + dx <= 0) {
if(nextDX > 0)
dx = nextDX;
else
dx = 0;
}
platform.setFrame(platform.getX() + dx, platform.getY(), platform.getWidth(), platform.getHeight());
platformIntervalX = new Interval((int)platform.getX(), (int)(platform.getX() + platform.getWidth()));
platformIntervalY = new Interval((int)(platform.getY() - platform.getHeight()), (int)platform.getY());
repaint();
}
The solution is not to use the KeyListener's key press for moving your sprite. The key is not to rely on the hardware-specific key press frequency, to use a Swing Timer to create your own frequency. Instead use Key Bindings and a Swing Timer. Start the time on key press and stop it on key release.
For example, run this code and press and release the up-arrow key:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class KeyBindingEg extends JPanel {
private static final String UP_KEY_PRESSED = "up key pressed";
private static final String UP_KEY_RELEASED = "up key released";
private static final int UP_TIMER_DELAY = 50;
private static final Color FLASH_COLOR = Color.red;
private Timer upTimer;
private JLabel label = new JLabel();
public KeyBindingEg() {
label.setFont(label.getFont().deriveFont(Font.BOLD, 32));
label.setOpaque(true);
add(label);
setPreferredSize(new Dimension(400, 300));
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
KeyStroke upKeyPressed = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
KeyStroke upKeyReleased = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true);
inputMap.put(upKeyPressed, UP_KEY_PRESSED);
inputMap.put(upKeyReleased, UP_KEY_RELEASED);
actionMap.put(UP_KEY_PRESSED, new UpAction(false));
actionMap.put(UP_KEY_RELEASED, new UpAction(true));
}
private class UpAction extends AbstractAction {
private boolean onKeyRelease;
public UpAction(boolean onKeyRelease) {
this.onKeyRelease = onKeyRelease;
}
@Override
public void actionPerformed(ActionEvent evt) {
if (!onKeyRelease) {
if (upTimer != null && upTimer.isRunning()) {
return;
}
System.out.println("key pressed");
label.setText(UP_KEY_PRESSED);
upTimer = new Timer(UP_TIMER_DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Color c = label.getBackground();
if (FLASH_COLOR.equals(c)) {
label.setBackground(null);
label.setForeground(Color.black);
} else {
label.setBackground(FLASH_COLOR);
label.setForeground(Color.white);
}
}
});
upTimer.start();
} else {
System.out.println("Key released");
if (upTimer != null && upTimer.isRunning()) {
upTimer.stop();
upTimer = null;
}
label.setText("");
}
}
}
private static void createAndShowGui() {
KeyBindingEg mainPanel = new KeyBindingEg();
JFrame frame = new JFrame("KeyBindingEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Edit
Or a better example, one that moves a sprite in any direction based on a key press of one of the arrow keys. No delay encountered:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;
@SuppressWarnings("serial")
public class KeyBindingEg2 extends JPanel {
enum Dir {
LEFT("Left", KeyEvent.VK_LEFT, -1, 0),
RIGHT("Right", KeyEvent.VK_RIGHT, 1, 0),
UP("Up", KeyEvent.VK_UP, 0, -1),
DOWN("Down", KeyEvent.VK_DOWN, 0, 1);
private String name;
private int keyCode;
private int deltaX;
private int deltaY;
private Dir(String name, int keyCode, int deltaX, int deltaY) {
this.name = name;
this.keyCode = keyCode;
this.deltaX = deltaX;
this.deltaY = deltaY;
}
public String getName() {
return name;
}
public int getKeyCode() {
return keyCode;
}
public int getDeltaX() {
return deltaX;
}
public int getDeltaY() {
return deltaY;
}
}
public static final int TIMER_DELAY = 10;
public static final int DELTA_X = 2;
public static final int DELTA_Y = DELTA_X;
public static final int SPRITE_WIDTH = 10;
public static final int SPRITE_HEIGHT = SPRITE_WIDTH;
private static final String PRESSED = "pressed";
private static final String RELEASED = "released";
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private Map<Dir, Boolean> dirMap = new EnumMap<>(Dir.class);
private int spriteX = 0;
private int spriteY = 0;
private BufferedImage sprite;
private Timer animationTimer = new Timer(TIMER_DELAY, new AnimationListener());
public KeyBindingEg2() {
for (Dir dir : Dir.values()) {
dirMap.put(dir, Boolean.FALSE);
}
sprite = createSprite();
setKeyBindings();
animationTimer.start();
}
private BufferedImage createSprite() {
BufferedImage sprt = new BufferedImage(SPRITE_WIDTH, SPRITE_HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = sprt.getGraphics();
g.setColor(Color.RED);
g.fillRect(0, 0, SPRITE_WIDTH, SPRITE_HEIGHT);
g.dispose();
return sprt;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (sprite != null) {
g.drawImage(sprite, spriteX, spriteY, this);
}
}
private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
for (Dir dir : Dir.values()) {
KeyStroke keyPressed = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, false);
KeyStroke keyReleased = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, true);
inputMap.put(keyPressed, dir.toString() + PRESSED);
inputMap.put(keyReleased, dir.toString() + RELEASED);
actionMap.put(dir.toString() + PRESSED, new DirAction(dir, PRESSED));
actionMap.put(dir.toString() + RELEASED, new DirAction(dir, RELEASED));
}
}
private class AnimationListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
int newX = spriteX;
int newY = spriteY;
for (Dir dir : Dir.values()) {
if (dirMap.get(dir)) {
newX += dir.getDeltaX() * DELTA_X;
newY += dir.getDeltaY() * DELTA_Y;
}
}
if (newX < 0 || newY < 0) {
return;
}
if (newX + SPRITE_WIDTH > getWidth() || newY + SPRITE_HEIGHT > getHeight()) {
return;
}
spriteX = newX;
spriteY = newY;
repaint();
}
}
private class DirAction extends AbstractAction {
private String pressedOrReleased;
private Dir dir;
public DirAction(Dir dir, String pressedOrReleased) {
this.dir = dir;
this.pressedOrReleased = pressedOrReleased;
}
@Override
public void actionPerformed(ActionEvent evt) {
if (pressedOrReleased.equals(PRESSED)) {
dirMap.put(dir, Boolean.TRUE);
} else if (pressedOrReleased.equals(RELEASED)) {
dirMap.put(dir, Boolean.FALSE);
}
}
}
private static void createAndShowGui() {
KeyBindingEg2 mainPanel = new KeyBindingEg2();
JFrame frame = new JFrame("KeyBindingEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
这篇关于Java的键盘输入 - 游戏开发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!