永远不会调用椭圆碰撞方法 - Java Swing

时间:2016-04-19 06:31:34

标签: java multithreading swing jpanel

我需要在java swing迷你游戏中计算2个椭圆的碰撞。

我有一个JPanel来吸引ArrayList个球Thread和我的球员。在我的非玩家球的run()方法中,我检查了球员球和球Thread ArrayList之间的碰撞。

问题是我的碰撞方法永远不会执行。它甚至没有达到我的碰撞if声明。永远不要打电话给方法。

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




}

JFrame并不特别,只需将JPanel添加到其中即可。

因此我的isCollision()方法永远不会被调用,即使它位于我run()的{​​{1}}方法中。怎么样?

3 个答案:

答案 0 :(得分:1)

您需要在repaint方法中调用while循环中的main方法,以便调用run()。你可以这样做:

panel.repaint():

此外,您必须调用run方法。你可以在球或面板中进行。

答案 1 :(得分:1)

ball.isAlive()总是返回false,因为你的线程还没有启动。如果要在paintComponent()方法中启动线程,则不应使用此方法。

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

    }






}

答案 2 :(得分:1)

您从未启动过Ball课程实施的主题。

ConcurrentModificationException是因为您正在向ArrayList添加球,如果您不在外部同步,则本质上是线程不安全的数据结构。在这里,您在迭代EDT(事件调度线程)中的列表时添加一个线程。要么在列表上同步,要么使用线程安全的数据结构(对于迭代,您仍然可能需要锁定完整列表)。

查看Collections.synchronizedListCopyOnWriteArrayList(后者不需要同步进行迭代)。

然而,每次插入和每次迭代的同步对我来说似乎效率很低,特别是因为你的目标是需要快速渲染和后台处理的游戏。但是,对于基本游戏来说可能就足够了。

作为旁注:更好的游戏技术是使用双缓冲:在后台线程中渲染游戏图形,例如:在BufferedImage上,完成后,切换两个缓冲区,使您刚绘制的缓冲区现在显示在屏幕上,另一个缓冲区可以再次用于绘制下一帧。您可能需要帧之间的同步检查点。但这稍微高级一些,所以如果你刚刚开始使用Java,我就不会花太多时间来处理它并保持简单。