2016-01-24 5 views
1

J'ai écrit un code qui génère le "serpent" dans le jeu Snake pour la pratique. (Dans le cas où vous n'êtes pas familier avec le serpent dans le jeu de serpent, il est un long serpent 5 boîtes avec une tête (créée avec JLabel) et les parties du corps (également créés avec JLabels) suivant la tête.)Java AWT/Swing Quand utiliser la méthode repaint()?

import java.awt.*; 
import java.awt.event.*; 
import java.util.Vector; 
import javax.swing.*; 

public class SnakeGameFrame extends JFrame { 
    Thread snakeThread; 
    GroundPanel p; 
    public SnakeGameFrame() { 
     super("Moving Snake!"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     p = new GroundPanel(); 
     setContentPane(p); 
     setSize(400,400); 
     setVisible(true); 
     p.requestFocus(); 
     snakeThread = new Thread(p); 
     snakeThread.start(); 
    } 

    class GroundPanel extends JPanel implements Runnable{ 
     static final int LEFT = 0; 
     static final int RIGHT = 1; 
     static final int UP = 2; 
     static final int DOWN = 3; 
     int direction; 
     Image img; 
     SnakeBody snakeBody; 
     final int delay = 200; 
     public GroundPanel() { 
      setLayout(null); 
      snakeBody = new SnakeBody(); 
      snakeBody.addIn(this); 
      direction = LEFT; 
      this.addKeyListener(new MyKeyListener()); 
      ImageIcon icon = new ImageIcon("twilight.jpg"); 
      img = icon.getImage(); 
     } 

     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      g.drawImage(img, 0,0,getWidth(), getHeight(), null); 
     } 
     public void run() { 
      while(true) { 
       try { 
        Thread.sleep(delay);     
        snakeBody.move(direction); 
       }catch(InterruptedException e) { 
        return; 
       } 
      } 
     } 

     class MyKeyListener extends KeyAdapter { 
      public void keyPressed(KeyEvent e) { 
       switch(e.getKeyCode()) { 
       case KeyEvent.VK_LEFT: 
        direction = LEFT; 
        break; 
       case KeyEvent.VK_RIGHT: 
        direction = RIGHT; 
        break; 
       case KeyEvent.VK_UP: 
        direction = UP; 
        break; 
       case KeyEvent.VK_DOWN: 
        direction = DOWN; 
        break; 
       } 
      } 
     } 
    } 

    class SnakeBody { 
     Vector<JLabel> v = new Vector<JLabel>(); 

     public SnakeBody() { 
      ImageIcon head = new ImageIcon("head.jpg"); 
      JLabel la = new JLabel(head); 
      la.setSize(head.getIconWidth(), head.getIconHeight()); 
      la.setLocation(100, 100); 
      v.add(la); 

      ImageIcon body = new ImageIcon("body.jpg");  
      for(int i=1; i<10; i++) { 
       la = new JLabel(body); 
       la.setSize(body.getIconWidth(), body.getIconHeight()); 
       la.setLocation(100+i*20, 100); 
       v.add(la); 
      } 
     } 

     public void addIn(JPanel p) { 
      for(int i=0; i<v.size(); i++) 
       p.add(v.get(i)); 
     } 

     public void move(int direction) { 
      for(int i=v.size()-1; i>0; i--) { 
       JLabel b = v.get(i); 
       JLabel a = v.get(i-1); 
       b.setLocation(a.getX(), a.getY()); 
      } 
      JLabel head = v.get(0); 
      switch(direction) { 
      case GroundPanel.LEFT : 
       head.setLocation(head.getX()-20, head.getY()); 
       break; 
      case GroundPanel.RIGHT : 
       head.setLocation(head.getX()+20, head.getY()); 
       break; 
      case GroundPanel.UP : 
       head.setLocation(head.getX(), head.getY()-20); 
       break; 
      case GroundPanel.DOWN : 
       head.setLocation(head.getX(), head.getY()+20); 
       break; 
      } 
     } 
    } 

    public static void main(String[] args) { 
     new SnakeGameFrame(); 
    } 
} 

ma question est afin de garder "mettre à jour" mon serpent, je pensais que je devrais utiliser la méthode repeindre() dans mon

public void run()

méthode

. Comme ceci

try {Thread.sleep (delay); snakeBody.move (direction); repeindre(); }

, mais il est apparu que cela fonctionne très bien sans lui .. J'ai lu beaucoup de messages sur repeindre() mais je ne comprends toujours pas quand je dois l'utiliser. Quelqu'un pourrait-il expliquer dans des terminologies noob-friendly? Merci :)

Répondre

2

Vous devez appeler repaint() lorsque le RepaintManager ne le fait pas déjà en votre nom, par exemple en mettant à jour une propriété liée telle que du texte ou des couleurs. Dans votre exemple, la modification de la taille et de l'emplacement d'un JLabel déclenche le repeint automatiquement.

Plus sérieusement, votre exemple est mal synchronisé de deux façons:

  • Il crée l'interface graphique sur le initial thread plutôt que sur le event dispatch thread.

  • Il met à jour les composants GUI sur un thread autre que le thread d'envoi d'événement sans synchroniser l'accès aux données partagées.

Au lieu de cela, utilisez un javax.swing.Timer pour accélérer l'animation. Votre implémentation de actionPerformed() sera appelée sur le thread d'envoi d'événement.

+0

Merci pour la réponse :) –

+0

Un exemple concurrentiel peut être trouvé [ici] (http://stackoverflow.com/a/31509204/230513). – trashgod