繁体   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