2016-02-04 24 views
-1

我使用匿名keyListener,但形状不动。当我运行我的程序时,它运行良好,我可以用颜色查看填充弧形状。然而,问题出在keyPressed方法上,当我按下方向键时,它似乎并没有激怒人心。当我在网上阅读一些答案时,我还在我的Jpanel上使用了setFocus。我仍然得到了同样的报告。任何帮助深表感谢。下面是我的代码:即使使用setFocus,移动形状不能在匿名keylistener上工作

public class PacMan { 

    public PacMan() 
    { 
     initializeUI(); 
    } 

    public void initializeUI() 
    { 
     JFrame frame = new JFrame("PacMan"); 
     PacManObject pacman = new PacManObject(); 
     pacman.setFocusable(true); 
     pacman.setRequestFocusEnabled(true); 

     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(600,600); 
     frame.setVisible(true); 
     frame.add(pacman); 

     pacman.addKeyListener(new PacManObject()); 


    } 

    public static void main(String[] args) { 
     Runnable runnable = new Runnable(){ 

      @Override 
      public void run() { 
       new PacMan(); 
      } 

     };EventQueue.invokeLater(runnable); 
    } 

    public class PacManObject extends JPanel implements KeyListener{ 

     int xLocation = 100; 
     int yLocation = 100; 
     int mouth = 265; 

     @Override 
     public void paintComponent(Graphics graphics) 
     { 
      super.paintComponent(graphics); 
      graphics.setColor(Color.yellow); 
      graphics.fillArc(xLocation, yLocation, 100, 100, 45, mouth); 
     } 

     @Override 
     public void keyPressed(KeyEvent keyboard) { 

      if(keyboard.getKeyCode() == KeyEvent.VK_RIGHT){ 
       System.out.print("hello"); 
       xLocation += 30; 
       System.out.print(xLocation); 
       repaint(); 
      } 
     } 

     @Override 
     public void keyTyped(KeyEvent ke) { 

     } 

     @Override 
     public void keyReleased(KeyEvent ke) { 

     } 

    } 

} 
+0

'...它不工作fine'是要帮助尽可能多的“我的电脑不能正常工作”。更具体一些,例如你会得到什么,你期望什么?你是否调试过你的代码来查看事件是否被触发? – Thomas

+0

@Thomas好吧我编辑我的问题随时检查 –

+0

您是否按下任何其他键时检查它是否被调用? – Thomas

回答

2

首先,我不得不重申你的代码结构很奇怪。 一个问题是,Pacman延伸JPanel - 为什么逃避我。

但是,这是问题的一部分,因为Pacman永远不会添加到任何框架或窗口,因此在该面板上调用repaint()不会做任何事情。

改为拨打pacman.repaint()frame.repaint()(在这种情况下两者都需要是最终的)。

+0

哎呀抱歉。没有注意到,我可以更新我的代码。 –

3

你创建了两个PacManObject对象

PacManObject pacman = new PacManObject(); // **** here **** 
pacman.setFocusable(true); 
pacman.setRequestFocusEnabled(true); 

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
frame.setSize(600,600); 
frame.setVisible(true); 
frame.add(pacman); 

pacman.addKeyListener(new PacManObject()); // **** and here **** 

当你真的应该通过创建两个可以只创建一个,因为你改变了一个2号的状态,但与第一次画,所以屏幕上不会显示更改。因此,而不是做这样的事情:

PacManObject pacman = new PacManObject(); 
pacman.setFocusable(true); 
pacman.setRequestFocusEnabled(true); 

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
frame.setSize(600,600); 
frame.setVisible(true); 
frame.add(pacman); 

pacman.addKeyListener(pacman); // **** note change **** 

更妙的是不让自己的GUI类实现监听器接口,因为这样做是给他们太多的责任 - 也就是说,它违反了班OOP原理的单责任的规则。

此外,更好地使用键绑定作为dup的会告诉你。

更好地使用摆动计时器作为您的游戏循环,而不是依赖按键,因为后者会导致初始移动的延迟。

例如:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.Shape; 
import java.awt.event.*; 
import java.awt.geom.*; 
import java.awt.image.BufferedImage; 
import java.util.EnumMap; 
import java.util.HashMap; 
import java.util.Map; 
import javax.swing.*; 

@SuppressWarnings("serial") 
public class PacMan2 extends JPanel implements DirMappable { 
    private static final int PREF_W = 600; 
    private static final int PREF_H = PREF_W; 
    private static final Color BG = Color.DARK_GRAY; 
    private static final int ANIMATION_DELAY = 15; 
    private int pmX = 100; 
    private int pmY = 100; 
    private EnumMap<Direction, Boolean> dirMap = new EnumMap<>(Direction.class); 

    private MyPacMan myPacMan = new MyPacMan(pmX, pmY, 30); 
    private Timer animationTimer; 

    public PacMan2() { 
     setBackground(BG); 

     setKeyBindings(); 

     animationTimer = new Timer(ANIMATION_DELAY, new AnimationListener(this)); 
     animationTimer.start(); 
    } 

    private void setKeyBindings() { 
     // fill the dirMap with false's -- no initial motion 
     for (Direction dir : Direction.values()) { 
      dirMap.put(dir, Boolean.FALSE); 
     } 

     // associate key code with Direction 
     Map<Integer, Direction> keyToDir = new HashMap<>(); 
     keyToDir.put(KeyEvent.VK_UP, Direction.UP); 
     keyToDir.put(KeyEvent.VK_DOWN, Direction.DOWN); 
     keyToDir.put(KeyEvent.VK_LEFT, Direction.LEFT); 
     keyToDir.put(KeyEvent.VK_RIGHT, Direction.RIGHT); 

     // get InputMap and ActionMap for binding 
     int condition = WHEN_IN_FOCUSED_WINDOW; 
     final InputMap inputMap = getInputMap(condition); 
     final ActionMap actionMap = getActionMap(); 

     // loop through the keyToDir Map and set up bindings 
     boolean[] keyPressed = { true, false }; 
     for (Integer keyCode : keyToDir.keySet()) { 
      Direction dir = keyToDir.get(keyCode); 
      for (boolean onKeyPress : keyPressed) { 
       // to make it clear how bindings work 
       boolean onKeyRelease = !onKeyPress; 
       KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0, onKeyRelease); 
       Object key = keyStroke.toString(); 
       inputMap.put(keyStroke, key); 
       // I prefer to use positive boolean variable for Action -- just a bit confusing 
       actionMap.put(key, new KeyBindingsAction(this, dir, onKeyPress)); 
      } 
     } 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D) g; 
     myPacMan.draw(g2); // have our pac man draw itself 
    } 

    // safest way to set the GUI's size 
    @Override 
    public Dimension getPreferredSize() { 
     if (isPreferredSizeSet()) { 
      return super.getPreferredSize(); 
     } 
     return new Dimension(PREF_W, PREF_H); 
    } 

    @Override 
    public void put(Direction dir, boolean pressed) { 
     dirMap.put(dir, pressed); 
    } 

    @Override 
    public boolean get(Direction dir) { 
     return dirMap.get(dir); 
    } 

    @Override 
    public void move(Direction dir) { 
     myPacMan.move(dir); // move our pacman 
    } 

    private static void createAndShowGui() { 
     PacMan2 mainPanel = new PacMan2(); 

     JFrame frame = new JFrame("Pac Man"); 
     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(() -> { 
      createAndShowGui(); 
     }); 
    } 
} 

class MyPacMan { 
    private static final Color COLOR = Color.YELLOW; 
    private static final int STEP = 3; // moves faster if this is larger 
    private int x; 
    private int y; 

    // for efficiency, draw PacMan as a BufferedImage 
    // if we want mouth to open and close, and if we want to 
    // have it change direction, we'll need a Map of images associated with 
    // the Direction enum 
    private BufferedImage pacManImage; 

    public MyPacMan(int x, int y, int w) { 
     this.x = x; 
     this.y = y; 
     double h = w; 
     double start = 45; 
     double extent = 360 - 2 * 45; 
     int type = Arc2D.PIE; 
     Shape shape = new Arc2D.Double(0, 0, w, h, start, extent, type); 
     pacManImage = new BufferedImage(w, w, BufferedImage.TYPE_INT_ARGB); 
     Graphics2D g2 = pacManImage.createGraphics(); 
     g2.setColor(COLOR); 
     // smooth drawing with key anti-aliasing 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     g2.fill(shape); 
     g2.dispose(); 
    } 

    public void move(Direction dir) { 
     x += dir.getIncrX() * STEP; 
     y += dir.getIncrY() * STEP; 
    } 

    public void draw(Graphics2D g2) { 
     if (pacManImage != null) { 
      g2.drawImage(pacManImage, x, y, null); 
     } 
    } 

    public int getX() { 
     return x; 
    } 

    public int getY() { 
     return y; 
    } 

} 

enum Direction { 
    UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0); 
    private int incrX; 
    private int incrY; 

    private Direction(int incrX, int incrY) { 
     this.incrX = incrX; 
     this.incrY = incrY; 
    } 

    public int getIncrX() { 
     return incrX; 
    } 

    public int getIncrY() { 
     return incrY; 
    } 
} 

// use an interface to encapsulate the methods of the GUI that need to be 
// exposed to the helper classes 
interface DirMappable { 
    void put(Direction dir, boolean pressed); 

    boolean get(Direction dir); 

    void move(Direction dir); 

    void repaint(); 
} 

@SuppressWarnings("serial") 
class KeyBindingsAction extends AbstractAction { 
    private Direction dir; 
    private boolean pressed; 
    private DirMappable dirMappable; 

    public KeyBindingsAction(DirMappable dirMappable, Direction dir, boolean pressed) { 
     this.dirMappable = dirMappable; 
     this.dir = dir; 
     this.pressed = pressed; 
    } 

    @Override 
    public void actionPerformed(ActionEvent evt) { 
     dirMappable.put(dir, pressed); 
    } 
} 

class AnimationListener implements ActionListener { 
    private DirMappable dirMappable; 

    public AnimationListener(DirMappable dirMappable) { 
     this.dirMappable = dirMappable; 
    } 

    @Override 
    public void actionPerformed(ActionEvent evt) { 
     boolean repaint = false; 
     for (Direction dir : Direction.values()) { 
      if (dirMappable.get(dir)) { 
       dirMappable.move(dir); 
       repaint = true; 
      } 
     } 
     if (repaint) { 
      dirMappable.repaint(); 
     } 
    } 
} 
+0

谢谢。但是你的回答太复杂了,我甚至都不明白。 :)。我只需要简单的解决方案。 –