关键重影问题

时间:2014-07-12 20:38:32

标签: java keypress keylistener japplet

我正在制作一个游戏而且我遇到了一个关键的重影问题(程序一次只能检测到一个按键,所以玩家不能对角线)。我正在看这个教程:https://www.youtube.com/watch?v=5UaEUrbpDPE 我按照他们所说的一切,但它仍然只能一次检测到一个键。

主:

public class Main extends JApplet implements Runnable, KeyListener {
    private static final long serialVersionUID = 1L;
    public static int width = 900;
    public static int height = 600;
    public static int fps = 60;
    public static Main instance;

    public static Ailoid ailoid = new Ailoid();
    public static Player player = new Player();

    // Initialize
    public void init() {
        setSize(width, height);
        setBackground(Color.white);
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        requestFocus();
        instance = this;

        ailoid.setLocation(new Location(100, 100));
        AlienManager.registerAlien(ailoid);
        player.setLocation(new Location(400, 400));
    }

    // Paint graphics
    public void paint(Graphics g) {
        super.paint(g);
        paintComponent(g);
    }
    public void paintComponent(Graphics g) {
        for (Alien alien : AlienManager.getAliens()) {
            Location loc = alien.getLocation();
            g.setColor(Color.GREEN);
            g.fillRect(loc.getX(), loc.getY(), 10, 25);
        }

        g.setColor(Color.BLUE);
        Location loc = Main.player.getLocation();
        g.fillRect(loc.getX(), loc.getY(), 10, 25);
    }

    // Thread start
    @Override
    public void start() {
        Thread thread = new Thread(this);
        thread.start();
    }
    // Thread stop
    @Override
    public void destroy() {

    }

    // Thread run
    @Override
    public void run() {
        Thread thread = new Thread(this);
        while (thread != null) {
            Updater.run();
            repaint();
            try {
                // 1000 divided by fps to get frames per second
                Thread.sleep(1000 / fps);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void keyPressed(KeyEvent evt) {
        if (!KeysDown.get().contains(evt.getKeyCode()))
            KeysDown.add(new Integer(evt.getKeyCode()));
        KeyPress.run(evt);
    }

    @Override
    public void keyReleased(KeyEvent evt) {
        KeysDown.remove(new Integer(evt.getKeyCode()));
    }

    @Override
    public void keyTyped(KeyEvent evt) {

    }
}

KeysDown:

public class KeysDown {
    private static ArrayList<Integer> keysDown = new ArrayList<Integer>();

    public static ArrayList<Integer> get() {
        return keysDown;
    }
    public static void add(Integer key) {
        keysDown.add(key);
    }
    public static void remove(Integer key) {
        keysDown.remove(key);
    }
}

按键:

public class KeyPress {
    public static void run(KeyEvent evt) {
        if (KeysDown.get().contains(KeyEvent.VK_RIGHT)) {
            Main.player.moveRight();
        }
        else if (KeysDown.get().contains(KeyEvent.VK_LEFT)) {
            Main.player.moveLeft();
        }
        else if (KeysDown.get().contains(KeyEvent.VK_DOWN)) {
            Main.player.moveDown();
        }
        else if (KeysDown.get().contains(KeyEvent.VK_UP)) {
            Main.player.moveUp();
        }
    }
}

谢谢!

1 个答案:

答案 0 :(得分:1)

正如我在之前的评论中提到的那样:

  • 不要直接在JApplet或任何顶级窗口中绘图。
  • 如果你给applet一个paintComponent方法,它就不会覆盖任何applet方法,也不会获得双缓冲的好处。
  • 而是在JPanel的paintComponent方法中绘制,从而获得双缓冲的好处。
  • 使用键绑定一个KeyListener。
  • 另外,我喜欢使用Swing Timer来进行简单的游戏循环。
  • 在下面的代码中,我使用名为Direction的枚举来封装屏幕上方向的想法。
  • 然后我将{for} Boolean.FALSEMap<Direction, Boolean>一起放入dirMap {/ 1}}。
  • 我连续运行一个Swing Timer,轮询这个Map的状态,并根据dirMap持有的布尔值状态移动一个sprite。
  • 我在键绑定操作中更改了地图保持值的状态。因此,如果按下向下键,其操作会将Map中的Direction.DOWN相关值更改为true,并且在释放时,Direction.DOWN相关值将更改回false。< / LI>

例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.EnumMap;

import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class AnimateExample extends JPanel {
   public static final String DUKE_IMG_PATH = // https://duke.kenai.com/iconSized/duke.gif
         "https://duke.kenai.com/iconSized/duke4.gif";
   private static final int PREF_W = 800;
   private static final int PREF_H = 800;
   private static final int TIMER_DELAY = 20;
   private static final String KEY_DOWN = "key down";
   private static final String KEY_RELEASE = "key release";
   public static final int TRANSLATE_SCALE = 3;
   private static final String BACKGROUND_STRING = "Use Arrow Keys to Move Image";
   private static final Font BG_STRING_FONT = new Font(Font.SANS_SERIF,
         Font.BOLD, 32);
   private EnumMap<Direction, Boolean> dirMap = 
         new EnumMap<AnimateExample.Direction, Boolean>(Direction.class);
   private BufferedImage image = null;
   private int imgX = 0;
   private int imgY = 0;
   private int bgStringX; 
   private int bgStringY; 

   public AnimateExample() {
      for (Direction dir : Direction.values()) {
         dirMap.put(dir, Boolean.FALSE);
      }
      try {
         URL imgUrl = new URL(DUKE_IMG_PATH);
         image = ImageIO.read(imgUrl);
      } catch (MalformedURLException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }

      new Timer(TIMER_DELAY, new TimerListener()).start();

      // here we set up our key bindings
      int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = getInputMap(condition);
      ActionMap actionMap = getActionMap();
      for (final Direction dir : Direction.values()) {

         // for the key down key stroke
         KeyStroke keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0,
               false);
         inputMap.put(keyStroke, dir.name() + KEY_DOWN);
         actionMap.put(dir.name() + KEY_DOWN, new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
               dirMap.put(dir, true);
            }
         });

         // for the key release key stroke
         keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, true);
         inputMap.put(keyStroke, dir.name() + KEY_RELEASE);
         actionMap.put(dir.name() + KEY_RELEASE, new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
               dirMap.put(dir, false);
            }
         });
      }

      FontMetrics fontMetrics = getFontMetrics(BG_STRING_FONT);
      int w = fontMetrics.stringWidth(BACKGROUND_STRING);
      int h = fontMetrics.getHeight();

      bgStringX = (PREF_W - w) / 2;
      bgStringY = (PREF_H - h) / 2;
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      g.setFont(BG_STRING_FONT);
      g.setColor(Color.LIGHT_GRAY);
      g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
            RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
      g.drawString(BACKGROUND_STRING, bgStringX, bgStringY);

      if (image != null) {
         g.drawImage(image, imgX, imgY, this);
      }
   }

   private class TimerListener implements ActionListener {
      public void actionPerformed(java.awt.event.ActionEvent e) {
         for (Direction dir : Direction.values()) {
            if (dirMap.get(dir)) {
               imgX += dir.getX() * TRANSLATE_SCALE;
               imgY += dir.getY() * TRANSLATE_SCALE;
            }
         }
         repaint();
      };
   }

   enum Direction {
      Up(KeyEvent.VK_UP, 0, -1), Down(KeyEvent.VK_DOWN, 0, 1), Left(
            KeyEvent.VK_LEFT, -1, 0), Right(KeyEvent.VK_RIGHT, 1, 0);

      private int keyCode;
      private int x;
      private int y;

      private Direction(int keyCode, int x, int y) {
         this.keyCode = keyCode;
         this.x = x;
         this.y = y;
      }

      public int getKeyCode() {
         return keyCode;
      }

      public int getX() {
         return x;
      }

      public int getY() {
         return y;
      }

   }

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

      JFrame frame = new JFrame("Animate Example");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
         }
      });
   }
}

有关Key Bindings的更多信息,请查看您可以找到的信息性教程here