2016-04-19 6 views
0

Ich muss eine 2-ovale Kollision in einem javaswing Minispiel berechnen.Oval Kollisionsverfahren nie aufgerufen - Java Swing

Ich habe eine JPanel die zieht meine ArrayList Bälle Thread 's und mein Spieler Ball. In der run() Methode meiner Nichtspielerbälle überprüfe ich für eine Kollision zwischen dem Spielerball und den Bällen ThreadArrayList.

Das Problem ist, dass meine Kollisions-Methode nie ausgeführt wird. Es kommt nicht einmal zu meiner Kollision if Aussage. Ruft die Methode nie an.

Ball.java:

public class Ball extends Thread 
{ 
    int x; 
    int y; 
    int velocity = 1; 
    public int radius = 20; 
    public boolean directionX = true; // True - right, false - left 
    public boolean directionY = false; // True - up, false - down 

    public static final int Y_STARTING_POSITION = 0; 
    public static final int X_STARTING_POSITION = 0; 

    public Ball() 
    { 
     switch (this.getStartingSide()) 
     { 
      case 0: // Left 
      { 
       this.directionX = true; 
       this.directionY = true; 

       this.x = this.getRandomHeight(); 
       this.y = this.getRandomWidth(); 

       break; 
      } 

      case 1: // Right 
      { 
       this.directionX = false; 
       this.directionY = false; 

       this.x = this.getRandomHeight(); 
       this.y = this.getRandomWidth(); 

       break; 
      } 

      case 2: // Top 
      { 
       this.directionX = true; 
       this.directionY = false; 

       this.x = this.getRandomWidth(); 
       this.y = this.getRandomHeight(); 

       break; 
      } 

      case 3: // Bottom 
      { 
       this.directionX = false; 
       this.directionY = true; 

       this.x = this.getRandomWidth(); 
       this.y = this.getRandomHeight(); 

       break; 
      } 

     } 
    } 


    public int getX() 
    { 
     return this.x; 
    } 
    public void setX(int x) 
    { 
     this.x = x; 
    } 
    public int getY() 
    { 
     return this.y; 
    } 
    public void setY(int y) 
    { 
     this.y = y; 
    } 

    public void move() 
    { 
     if (this.directionX) // Right 
     { 
      this.x += this.velocity; 
     } 
     else // Left 
     { 
      this.x -= this.velocity; 
     } 
     if (this.directionY) // Up 
     { 
      this.y -= this.velocity; 
     } 
     else // Down 
     { 
      this.y += this.velocity; 
     } 
    } 

    @Override 
    public void run() 
    { 
     try 
     { 
      this.isCollision(); // Never called 
      Thread.sleep(20); 
     } 
     catch (InterruptedException e) 
     { 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * Get a random number varies from 0 to the screen width. 
    * 
    * @return The random number. 
    * 
    */ 
    public int getRandomWidth() 
    { 
     Random random = new Random(); 
     return random.nextInt((Program.getPanelWidth() - 0) + 1) + 0; // Minimum = 0,maximum = Program.panelWidth 
    } 
    /** 
    * Get a random number varies from 0 to the screen height. 
    * 
    * @return The random number. 
    * 
    */ 
    public int getRandomHeight() 
    { 
     Random random = new Random(); 
     return random.nextInt((Program.getPanelHeight() - 0) + 1) + 0; // Minimum = 0,maximum = Program.panelHeight 
    } 
    /** 
    * Get the starting side of a ball. 
    * 
    * Left - 0. 
    * Right - 1. 
    * Top - 2. 
    * Bottom - 3. 
    * 
    * @return 
    * 
    */ 
    public int getStartingSide() 
    { 
     Random random = new Random(); 
     return random.nextInt((4 - 0) + 1) + 0; // Minimum = 0,maximum = 3 
    } 


    public void isCollision() 
    { 
     System.out.println("SSSSSSSSSSSSSSSS"); 
     if (Math.sqrt(Math.pow(MyPanel.playerX + MyPanel.playerRadius - this.getX() + this.radius,2) 
       + Math.pow(MyPanel.playerY + MyPanel.playerRadius - this.getY() + this.radius,2)) 
       <= MyPanel.playerRadius + this.radius) // A collision 
     { 
      System.exit(0); 
     } 
    } 


} // End of Ball class 

MyPanel.java:

public class MyPanel extends JPanel implements KeyListener 
{ 
    private static final long serialVersionUID = 1L; 

    private static final Color BACKGROUND_COLOR = Color.WHITE; 
    private static final Color NPC_BALLS_COLOR = Color.RED; 

    // The player is an oval 
    public static int playerRadius = 35; 

    public static int playerX; 
    public static int playerY; 

    // True - first player position, false - otherwise 
    private boolean playerPosition = true; 

    // Array of all the balls threads 
    public static ArrayList<Ball> balls = new ArrayList<Ball>(); 


    public MyPanel() 
    { 
     this.setBackground(MyPanel.BACKGROUND_COLOR); 
     this.setFocusable(true); 
     this.addKeyListener(this); 

     new Timer(10,new UpdateUI()); 
    } 


    // Drawing 

    @Override 
    protected void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 

     final double PANEL_WIDTH = this.getWidth(); 
     final double PANEL_HEIGHT = this.getHeight(); 

     if (this.playerPosition) 
     { 
      MyPanel.playerX = (int)(PANEL_WIDTH/2 - MyPanel.playerRadius); 
      MyPanel.playerY = (int)(PANEL_HEIGHT/2 - MyPanel.playerRadius); 
      this.playerPosition = false; 
     } 

     // Drawing the player 
     g.setColor(Color.BLACK); 
     g.fillOval(playerX,playerY, MyPanel.playerRadius * 2, MyPanel.playerRadius * 2); 

     // Drawing npc's balls 
     g.setColor(MyPanel.NPC_BALLS_COLOR); 
     for (Ball ball: MyPanel.balls) // ConcurrentModificationException 
     { 
      if (ball.isAlive()) 
      { 
       ball.start(); 
      } 

      ball.move(); 
      repaint(); 
      g.fillOval(ball.getX(), ball.getY(), 
        ball.radius * 2, ball.radius * 2); 
     } 

    } 

    // Keyboard listeners 

    @Override 
    public void keyPressed(KeyEvent e) 
    { 
     switch (e.getKeyCode()) 
     { 
      case KeyEvent.VK_W: // Up 
      { 
       MyPanel.playerY -= 10; 
       repaint(); 
       break; 
      } 
      case KeyEvent.VK_S: // Down 
      { 
       MyPanel.playerY += 10; 
       repaint(); 
       break; 
      } 
      case KeyEvent.VK_D: // Right 
      { 
       MyPanel.playerX += 10; 
       repaint(); 
       break; 
      } 
      case KeyEvent.VK_A: // Left 
      { 
       MyPanel.playerX -= 10; 
       repaint(); 
       break; 
      } 
     } 
    } 

    @Override 
    public void keyReleased(KeyEvent e) 
    { 

    } 

    @Override 
    public void keyTyped(KeyEvent e) 
    { 

    } 

    public class UpdateUI implements ActionListener 
    { 

     @Override 
     public void actionPerformed(ActionEvent e) 
     { 
      repaint(); 
     } 

    } 






} // End of MyPanel class 

Program.java:

public class Program 
{ 
    private static int panelWidth; 
    private static int panelHeight; 

    public static void main(String[] args) 
    { 
     MyFrame frame = new MyFrame(); 

     Program.panelWidth = frame.getWidth(); 
     Program.panelHeight = frame.getHeight(); 

     // Generate a ball each 2 seconds 
     while (true) 
     { 
      try 
      { 
       MyPanel.balls.add(new Ball()); 


       Thread.sleep(500); 
      } 
      catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 
     } 

    } // End of main method 

    public static int getPanelWidth() 
    { 
     return Program.panelWidth; 
    } 


    public static int getPanelHeight() 
    { 
     return Program.panelHeight; 
    } 




} 

Der 012.ist nichts besonderes und fügt nur die JPanel hinzu und so.

Also meine isCollision() Methode wird nie aufgerufen, auch wenn es auf meiner run() Methode meiner Thread ist. Woher?

Antwort

1

Sie haben nie den von Ihrer Ball Klasse implementierten Thread gestartet.

Die ConcurrentModificationException ist aufgrund der Tatsache, dass Sie Bälle zu einem ArrayList hinzufügen, die von Natur aus eine Thread-unsichere Datenstruktur ist, wenn Sie nicht extern synchronisieren. Hier fügen Sie einen Thread hinzu, während Sie die Liste im EDT (Event Dispatch Thread) durchlaufen. Entweder synchronisieren Sie in der Liste oder Sie verwenden eine threadsichere Datenstruktur (für die Iteration müssen Sie möglicherweise immer noch die vollständige Liste sperren).

Sehen Sie sich Collections.synchronizedList oder CopyOnWriteArrayList an (Letzteres muss nicht für die Iteration synchronisiert werden).

Allerdings scheint mir die Synchronisation bei jedem Einfügen und jeder Iteration sehr ineffizient, vor allem, weil Sie ein Spiel anstreben, das schnelles Rendering und Hintergrundverarbeitung erfordert. Es kann jedoch für ein einfaches Spiel ausreichen.

Als Nebenbemerkung: eine bessere Technik für ein Spiel wäre die Verwendung von Double-Buffering: Rendern Sie die Spielgrafiken in einem Hintergrund-Thread, z.Bei einem BufferedImage, und wenn Sie fertig sind, wechseln Sie die beiden Puffer, so dass der gerade gezeichnete auf dem Bildschirm angezeigt wird, und der andere wieder zum Zeichnen des nächsten Rahmens verwendet werden kann. Möglicherweise benötigen Sie einen Synchronisierungs-Checkpoint zwischen Frames. Aber das ist etwas weiter fortgeschritten, also wenn Sie nur in Java anfangen, würde ich nicht zu viel Zeit damit verbringen und die Dinge einfach halten.

+0

Welche 'Thread' sichere Datenstrukturen gibt es? Und wie synchronisiere ich eine 'ArrayList'? – God

+0

Ich habe die Antwort aktualisiert. – Timmos

1

Sie müssen die repaint Methode in Ihrer while-Schleife in der main-Methode aufrufen, damit run() aufgerufen werden kann. Sie können es mit diesem tun:

panel.repaint(): 

Außerdem müssen Sie die run Methode aufrufen. Sie können es in Ball oder im Panel tun.

1

ball.isAlive() geben Sie immer falsch zurück, weil Ihr Thread nicht gestartet wurde. Wenn Sie Ihre Threads in der Methode paintComponent() starten möchten, sollten Sie diese Methode nicht verwenden.

public class MyPanel extends JPanel implements KeyListener 
{ 
    private static final long serialVersionUID = 1L; 

    private static final Color BACKGROUND_COLOR = Color.WHITE; 
    private static final Color NPC_BALLS_COLOR = Color.RED; 

    // The player is an oval 
    public static int playerRadius = 35; 

    public static int playerX; 
    public static int playerY; 

    // True - first player position, false - otherwise 
    private boolean playerPosition = true; 
    private boolean ballsStarted; 

    // Array of all the balls threads 
    public static ArrayList<Ball> balls = new ArrayList<Ball>(); 


    public MyPanel() 
    { 
     this.setBackground(MyPanel.BACKGROUND_COLOR); 
     this.setFocusable(true); 
     this.addKeyListener(this); 

     new Timer(10,new UpdateUI()); 
    } 


    // Drawing 

    @Override 
    protected void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 

     final double PANEL_WIDTH = this.getWidth(); 
     final double PANEL_HEIGHT = this.getHeight(); 

     if (this.playerPosition) 
     { 
      MyPanel.playerX = (int)(PANEL_WIDTH/2 - MyPanel.playerRadius); 
      MyPanel.playerY = (int)(PANEL_HEIGHT/2 - MyPanel.playerRadius); 
      this.playerPosition = false; 
     } 

     // Drawing the player 
     g.setColor(Color.BLACK); 
     g.fillOval(playerX,playerY, MyPanel.playerRadius * 2, MyPanel.playerRadius * 2); 

     // Drawing npc's balls 
     g.setColor(MyPanel.NPC_BALLS_COLOR); 
     for (Ball ball: MyPanel.balls) // ConcurrentModificationException 
     { 
      if (!ballsStarted) 
      { 
       ball.start(); 
      } 

      ball.move(); 
      repaint(); 
      g.fillOval(ball.getX(), ball.getY(), 
        ball.radius * 2, ball.radius * 2); 
     } 
     ballsStarted = true; 
    } 

    // Keyboard listeners 

    @Override 
    public void keyPressed(KeyEvent e) 
    { 
     switch (e.getKeyCode()) 
     { 
      case KeyEvent.VK_W: // Up 
      { 
       MyPanel.playerY -= 10; 
       repaint(); 
       break; 
      } 
      case KeyEvent.VK_S: // Down 
      { 
       MyPanel.playerY += 10; 
       repaint(); 
       break; 
      } 
      case KeyEvent.VK_D: // Right 
      { 
       MyPanel.playerX += 10; 
       repaint(); 
       break; 
      } 
      case KeyEvent.VK_A: // Left 
      { 
       MyPanel.playerX -= 10; 
       repaint(); 
       break; 
      } 
     } 
    } 

    @Override 
    public void keyReleased(KeyEvent e) 
    { 

    } 

    @Override 
    public void keyTyped(KeyEvent e) 
    { 

    } 

    public class UpdateUI implements ActionListener 
    { 

     @Override 
     public void actionPerformed(ActionEvent e) 
     { 
      repaint(); 
     } 

    } 






} 
+0

Zeit zu einem Schritt vorwärts :-), [zum Beispiel] (http://StackOverflow.com/A/7940227/714968) – mKorbel