Ключевые проблемы с ореолом

1

Я делаю игру, и я столкнулся с ключевой проблемой ореолов (где программа обнаруживает только одно нажатие одновременно, поэтому игрок не может идти по диагонали). Я смотрел этот учебник: 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();
        }
    }
}

Спасибо!

  • 3
    Проблема в KeyPress , не KeyPress , if-elseif-elseif-... это запретит движение по диагонали. Используйте только if без else . ( docs.oracle.com/javase/tutorial/java/nutsandbolts/if.html )
Теги:
keylistener
keypress
japplet

1 ответ

1
Лучший ответ

Опять же, как я упомянул в предыдущих комментариях:

  • Не нарисуйте прямо на JApplet или в любом верхнем уровне окна.
  • Если вы дадите вашему аплету метод paintComponent, он не переопределит какие-либо методы апплета и не получит преимущества двойной буферизации.
  • Вместо этого нарисуйте метод paintComponent JPanel, тем самым получив преимущество двойной буферизации.
  • Используйте привязки клавиш, а не KeyListener.
  • Кроме того, мне нравится использовать Swing Timer для простых игровых петель.
  • В приведенном ниже коде я использую перечисление под названием Direction чтобы инкапсулировать идею направлений на экране.
  • Затем я помещаю для Directions вместе с Boolean.FALSE в Map<Direction, Boolean> называемый dirMap.
  • Я запускаю таймер Swing Timer, опросив состояние этой Карты и перемещая спрайт на основе состояния булевых элементов, хранящегося в dirMap.
  • Я изменяю состояние сохраненных значений карты в своих действиях по привязке клавиш. Поэтому, если нажата клавиша "вниз", ее действие изменит связанное с Direction.DOWN значение в Map на значение true, а при его выпуске связанное значение Direction.DOWN будет изменено на false.

Например:

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();
         }
      });
   }
}

Подробнее о ключевых привязках, пожалуйста, ознакомьтесь с информативным руководством, которое вы можете найти здесь.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню