监听器和计时器之间的通信

时间:2016-05-14 01:58:24

标签: java swing timer listeners

我对java很新,我对如何做到这一点很困惑。我有一个关键的听众,听取WASD,表明我的蛇的运动。关键监听器会更改Snakes段的x和y位置。我有一个定时器链接到一个名为“Listener”的监听器,它将动作重新映射到缓冲区和屏幕上。我的问题是,为什么我的键监听器指示的运动不能进入缓冲区?另外,我知道我的移动功能是有效的,但是我要知道我的移动功能。在计时器中工作。最后一点,这是一场我刚刚开始的Snake游戏。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class SnekePanel extends JPanel
{
    private static final int FRAME1 = 1000;
    private static final int FRAME2 = 1000;
    private static final Color BACKGROUND = new Color(0, 0, 0);
    private BufferedImage myImage;
    private Graphics myBuffer;
    private Sneke snek;
    private Food food;
    private Timer t;
    private int points = 0;
    public SnekePanel()
    {
      myImage =  new BufferedImage(FRAME1, FRAME2, BufferedImage.TYPE_INT_RGB);
      myBuffer = myImage.getGraphics();
      myBuffer.setColor(BACKGROUND);
      myBuffer.fillRect(0, 0, FRAME1,FRAME2);
      int xPos = (int)(Math.random()*(FRAME1-100) + 50);
      int yPos = (int)(Math.random()*(FRAME2-100)+ 50);
      food = new Food(xPos, yPos, 10, Color.RED);
      snek = new Sneke(200,200,1,Color.WHITE);
      t = new Timer(5, new Listener());
      t.start();
      addKeyListener(new Key());
      setFocusable(true);
   }

   public void paintComponent(Graphics g)
   {
      g.drawImage(myImage, 0, 0, getWidth(), getHeight(), null);
   }

   private class Key extends KeyAdapter
   {
      public void keyPressed(KeyEvent e)
      {
         if(e.getKeyCode() == KeyEvent.VK_W)
         {
            snek.move(1);
         }
         if(e.getKeyCode() == KeyEvent.VK_A)
         {
            snek.move(2);
         }
         if(e.getKeyCode() == KeyEvent.VK_S)
         {
            snek.move(3);
         }
         if(e.getKeyCode() == KeyEvent.VK_D)
         {
            snek.move(4);
         }

      }

   }

   private class Listener implements ActionListener
   {
      public void actionPerformed(ActionEvent e)
      {
         if(snek.checkBlock() != 0)
         {
            myBuffer.setColor(BACKGROUND);
            myBuffer.fillRect(0,0,FRAME1,FRAME2);
            snek.move(4);
            collide(snek, food);
            food.draw(myBuffer);
            snek.draw(myBuffer);
            myBuffer.setColor(Color.BLACK);
            repaint();
         }  
      } 
   }  

   private void collide(Sneke b, Food pd)
   {
      int sx = b.getX(snek.getLength()-1);
      int sy = b.getY(snek.getLength()-1);
      int fx = pd.getX();
      int fy = pd.getY();
      if(sx == sy && fx == fy)
      {
         snek.setLength(snek.getLength()+1);
      }
   }
}

1 个答案:

答案 0 :(得分:2)

  

为什么我的键监听器指示的移动不会进入缓冲区?

在我看来,一个更重要的问题是:为什么你认为它应该进入缓冲区?您只是在调用snek.move(4)之后绘制缓冲区,因此看起来只有那样才会进入缓冲区。

我自己,我会以不同的方式做事,包括(除其他事项外)

  • 我会创建一个int字段 - 或者更好的一个方向枚举,它封装了up,down,left和right。
  • 我给我的GUI上面有一个字段,我将它设置在KeyListener中。
  • 我实际上更喜欢使用Key Bindings而不是KeyListener,因为在焦点问题上它不那么狡猾,但两者都可以工作。
  • 在我的计时器中,我会根据字段
  • 中的值的状态移动精灵

例如,尝试运行:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import java.util.List;

import javax.swing.*;


@SuppressWarnings("serial")
public class SnakePanel extends JPanel {
    // size of the GUI
    private static final int PREF_W = 1000;
    private static final int PREF_H = 800;

    // background and snake color
    private static final Color BG = Color.BLACK;
    private static final Color SNAKE_COLOR = Color.RED;
    private static final int SEGMENT_WIDTH = 20;

    // distance moved in each timer tick, and time between each tick
    private static final int DELTA = 5;
    private static final int TIMER_DELAY = 40; // in msecs

    // number of segments in the worm
    private static final int WORM_LENGTH = 80;

    // initial direction
    private Direction direction = Direction.RIGHT;

    // initial point
    private Point point = new Point(PREF_W / 2, PREF_H / 2);

    // Snake is little more than a List of Points
    private List<Point> snakePointList = new LinkedList<>();

    public SnakePanel() {
        // set background color
        setBackground(BG);

        // fill snake list with points
        for (int i = 0; i < WORM_LENGTH; i++) {
            snakePointList.add(new Point(point));
        }

        // set key bindings 
        setKeyBindings();

        // create and start Timer
        new Timer(TIMER_DELAY, new TimerListener()).start();
    }

    // set up our key bindings
    private void setKeyBindings() {
        int condition = WHEN_IN_FOCUSED_WINDOW;
        InputMap inputMap = getInputMap(condition);
        ActionMap actionMap = getActionMap();

        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
        setKeyStroke(inputMap, actionMap, keyStroke, Direction.UP);        
        keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
        setKeyStroke(inputMap, actionMap, keyStroke, Direction.DOWN);
        keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
        setKeyStroke(inputMap, actionMap, keyStroke, Direction.LEFT);
        keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
        setKeyStroke(inputMap, actionMap, keyStroke, Direction.RIGHT);
    }

    private void setKeyStroke(InputMap inputMap, ActionMap actionMap, KeyStroke keyStroke,
            Direction dir) {
        inputMap.put(keyStroke, keyStroke.toString());
        actionMap.put(keyStroke.toString(), new MyKeyAction(dir));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        // smooth out our graphics
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // draw each oval in the Snake
        for (Point pt : snakePointList) {
            drawPoint(g2, pt);
        }
    }

    private void drawPoint(Graphics2D g2, Point pt) {
        g2.setColor(SNAKE_COLOR);

        // The pt is actually the center point
        // so we need to draw an oval that is centered on this point
        int x = pt.x - SEGMENT_WIDTH / 2;
        int y = pt.y - SEGMENT_WIDTH / 2;
        g2.drawOval(x, y, SEGMENT_WIDTH, SEGMENT_WIDTH);
    }

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

    // Action used by key binding
    private class MyKeyAction extends AbstractAction {
        private Direction dir;

        public MyKeyAction(Direction dir) {
            this.dir = dir;
        }

        public void actionPerformed(ActionEvent e) {
            // all it does is set the Direction direction enum field
            // for this GUI 
            // the Timer then uses this field
            SnakePanel.this.direction = dir;
        };
    }

    // timer ActionListener
    private class TimerListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            // create a new Point whose direction depends
            // on the direction field * multiplier, DELTA
            int x = point.x + direction.getX() * DELTA;
            int y = point.y + direction.getY() * DELTA;

            // create new point and add to snakePointList
            point = new Point(x, y);
            snakePointList.add(point);
            // remove last point in list
            snakePointList.remove(0);
            repaint();
        }
    }

    // Direction enum
    enum Direction {
        UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);

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

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }
    }

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

        JFrame frame = new JFrame("SnakePanel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}
相关问题