2016-05-14 29 views
0

即时通讯相当新的Java和我很困惑如何做到这一点。我有一个听取WASD的关键听众,它指示我的Snake的移动。关键听众改变了我的蛇段的x和y位置。我有一个计时器链接到名为“Listener”的监听器,该监听器将移动重新绘制到缓冲区和屏幕上。我的问题是,为什么我的关键听众指示的移动不会将其放到缓冲区中?另外,我知道我的移动功能工作原因是snek.move(4);在计时器中工作。最后说明,这是一个我几乎没有开始的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); 
     } 
    } 
} 

回答

2

为什么我的钥匙听众表示运动没有使它的缓冲区?

在我心中一个更重要的问题是:为什么你认为它应该做出缓冲?在调用snek.move(4)之后,您只绘制了缓冲区,所以看起来只有这样才能进入缓冲区。

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

  • 我会创造一个int领域 - 或者更好的封装上,下方向枚举,左,右。
  • 我会给我的图形用户界面这个上面的领域,我将它设置在KeyListener中。
  • 我实际上更喜欢使用键绑定而不是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()); 
    } 
} 
+0

很好,因为关键监听改变蛇的领域,然后蛇在计时器重新绘制,我希望计时器反映关键听众的I/O。 –

+0

@SompTingWong:好吧,因为你的计时器改变了字段,所以你需要调整你的期望。也许你不应该在定时器中设置蛇的状态。 –

+0

@SompTingWong:查看使用密钥绑定的示例请 –