簡體   English   中英

橢圓調用方法從未被調用-Java Swing

[英]Oval collision method never called - Java Swing

我需要在java swing迷你游戲中計算2個橢圓形碰撞。

我有一個JPanel ,它繪制了球ThreadArrayList和球員球。 在非球員球的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添加到其中。

因此,即使位於Thread run()方法上,也永遠不會調用我的isCollision()方法。 怎么會?

您需要在main方法的while循環中調用repaint方法,以便可以調用run() 您可以這樣做:

panel.repaint():

另外,您必須調用run方法。 您可以在球中或面板中進行操作。

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

    }






}

您從未啟動過Ball類實現的Thread。

ConcurrentModificationException是由於您要向ArrayList添加球這一事實,如果您不從外部進行同步,則ArrayList本質上是線程不安全的數據結構。 在這里,您在迭代EDT(事件調度線程)中的列表時添加了線程。 您要么在列表上進行同步,要么使用線程安全的數據結構(對於迭代,您可能仍需要鎖定完整列表)。

看一下Collections.synchronizedListCopyOnWriteArrayList (后者不需要同步進行迭代)。

但是,每次插入和每次迭代的同步對我來說似乎效率都很低,尤其是因為您的目標是需要快速渲染和背景處理的游戲。 不過,對於一個基本游戲來說可能就足夠了。

附帶說明:一種更好的游戲技術是使用雙緩沖:在后台線程中(例如在BufferedImage上)渲染游戲圖形,完成后,切換兩個緩沖區,以便您剛才繪制的緩沖區現在顯示在屏幕上,另一個可以再次用於繪制下一幀。 您可能需要幀之間的同步檢查點。 但這稍微先進一點,因此,如果您只是從Java開始,我不會花太多時間在Java上並使事情保持簡單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM