Java Balle Rebondissante


J'essaie d'écrire une application Java qui dessine plusieurs balles à l'écran qui rebondissent sur les bords du cadre. Je peux dessiner avec succès une balle. Cependant, lorsque j'ajoute la deuxième balle, elle écrase la balle initiale que j'ai dessinée. Le code est:

import java.awt.*;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;

public class Ball extends JPanel implements Runnable {

    List<Ball> balls = new ArrayList<Ball>();   
Color color;
int diameter;
long delay;
private int x;
private int y;
private int vx;
private int vy;

public Ball(String ballcolor, int xvelocity, int yvelocity) {
    if(ballcolor == "red") {
        color = Color.red;
    }
    else if(ballcolor == "blue") {
        color = Color.blue;
    }
    else if(ballcolor == "black") {
        color = Color.black;
    }
    else if(ballcolor == "cyan") {
        color = Color.cyan;
    }
    else if(ballcolor == "darkGray") {
        color = Color.darkGray;
    }
    else if(ballcolor == "gray") {
        color = Color.gray;
    }
    else if(ballcolor == "green") {
        color = Color.green;
    }
    else if(ballcolor == "yellow") {
        color = Color.yellow;
    }
    else if(ballcolor == "lightGray") {
        color = Color.lightGray;
    }
    else if(ballcolor == "magenta") {
        color = Color.magenta;
    }
    else if(ballcolor == "orange") {
        color = Color.orange;
    }
    else if(ballcolor == "pink") {
        color = Color.pink;
    }
    else if(ballcolor == "white") {     
        color = Color.white;
    }
    diameter = 30;
    delay = 40;
    x = 1;
    y = 1;
    vx = xvelocity;
    vy = yvelocity;
}

protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D)g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g.setColor(color);
    g.fillOval(x,y,30,30); //adds color to circle
    g.setColor(Color.black);
    g2.drawOval(x,y,30,30); //draws circle
}

public void run() {
    while(isVisible()) {
        try {
            Thread.sleep(delay);
        } catch(InterruptedException e) {
            System.out.println("interrupted");
        }
        move();
        repaint();
    }
}

public void move() {
    if(x + vx < 0 || x + diameter + vx > getWidth()) {
        vx *= -1;
    }
    if(y + vy < 0 || y + diameter + vy > getHeight()) {
        vy *= -1;
    }
    x += vx;
    y += vy;
}

private void start() {
    while(!isVisible()) {
        try {
            Thread.sleep(25);
        } catch(InterruptedException e) {
            System.exit(1);
        }
    }
    Thread thread = new Thread(this);
    thread.setPriority(Thread.NORM_PRIORITY);
    thread.start();
}

public static void main(String[] args) {
    Ball ball1 = new Ball("red",3,2);
    Ball ball2 = new Ball("blue",6,2);
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().add(ball1);
    f.getContentPane().add(ball2);
    f.setSize(400,400);
    f.setLocation(200,200);
    f.setVisible(true);
    new Thread(ball1).start();
    new Thread(ball2).start();
}
}

Je voulais créer une liste de balles, puis parcourir le dessin de chacune des balles, mais j'ai toujours du mal à ajouter les deux balles dans le volet de contenu.

Merci pour toute aide.

Author: Hovercraft Full Of Eels, 2012-10-23

4 answers

Avec votre approche actuelle...

  • Le principal problème que je peux voir est que vous placez deux composants opaques l'un sur l'autre...en fait, vous pouvez trouver que vous contournez l'un d'eux pour l'autre...
  • Vous devriez utiliser un gestionnaire de mise en page null, sinon il prendra le relais et mettra en page vos balles comme bon lui semble.
  • Vous devez vous assurer que vous contrôlez la taille et l'emplacement du volet de la balle. Cela signifie que vous avez repris le rôle de mise en page gestionnaire...
  • Vous devez randomiser la vitesse et l'emplacement des balles pour leur donner moins de chances de commencer au même endroit et de se déplacer au même endroit...
  • Ne mettre à jour le Ball que dans le contexte de l'EDT.
  • Vous n'avez pas vraiment besoin des valeurs X/Y, vous pouvez utiliser les panneaux.

.

public class AnimatedBalls {

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

    public AnimatedBalls() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new Balls());
                frame.setSize(400, 400);
                frame.setVisible(true);
            }
        });
    }

    public class Balls extends JPanel {

        public Balls() {
            setLayout(null);
            // Randomize the speed and direction...
            add(new Ball("red", 10 - (int) Math.round((Math.random() * 20)), 10 - (int) Math.round((Math.random() * 20))));
            add(new Ball("blue", 10 - (int) Math.round((Math.random() * 20)), 10 - (int) Math.round((Math.random() * 20))));
        }
    }

    public class Ball extends JPanel implements Runnable {

        Color color;
        int diameter;
        long delay;
        private int vx;
        private int vy;

        public Ball(String ballcolor, int xvelocity, int yvelocity) {
            if (ballcolor == "red") {
                color = Color.red;
            } else if (ballcolor == "blue") {
                color = Color.blue;
            } else if (ballcolor == "black") {
                color = Color.black;
            } else if (ballcolor == "cyan") {
                color = Color.cyan;
            } else if (ballcolor == "darkGray") {
                color = Color.darkGray;
            } else if (ballcolor == "gray") {
                color = Color.gray;
            } else if (ballcolor == "green") {
                color = Color.green;
            } else if (ballcolor == "yellow") {
                color = Color.yellow;
            } else if (ballcolor == "lightGray") {
                color = Color.lightGray;
            } else if (ballcolor == "magenta") {
                color = Color.magenta;
            } else if (ballcolor == "orange") {
                color = Color.orange;
            } else if (ballcolor == "pink") {
                color = Color.pink;
            } else if (ballcolor == "white") {
                color = Color.white;
            }
            diameter = 30;
            delay = 100;

            vx = xvelocity;
            vy = yvelocity;

            new Thread(this).start();

        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;

            int x = getX();
            int y = getY();

            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setColor(color);
            g.fillOval(0, 0, 30, 30); //adds color to circle
            g.setColor(Color.black);
            g2.drawOval(0, 0, 30, 30); //draws circle
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(30, 30);
        }

        public void run() {

            try {
                // Randamize the location...
                SwingUtilities.invokeAndWait(new Runnable() {
                    @Override
                    public void run() {
                        int x = (int) (Math.round(Math.random() * getParent().getWidth()));
                        int y = (int) (Math.round(Math.random() * getParent().getHeight()));

                        setLocation(x, y);
                    }
                });
            } catch (InterruptedException exp) {
                exp.printStackTrace();
            } catch (InvocationTargetException exp) {
                exp.printStackTrace();
            }

            while (isVisible()) {
                try {
                    Thread.sleep(delay);
                } catch (InterruptedException e) {
                    System.out.println("interrupted");
                }

                try {
                    SwingUtilities.invokeAndWait(new Runnable() {
                        @Override
                        public void run() {
                            move();
                            repaint();
                        }
                    });
                } catch (InterruptedException exp) {
                    exp.printStackTrace();
                } catch (InvocationTargetException exp) {
                    exp.printStackTrace();
                }
            }
        }

        public void move() {

            int x = getX();
            int y = getY();

            if (x + vx < 0 || x + diameter + vx > getParent().getWidth()) {
                vx *= -1;
            }
            if (y + vy < 0 || y + diameter + vy > getParent().getHeight()) {
                vy *= -1;
            }
            x += vx;
            y += vy;

            // Update the size and location...
            setSize(getPreferredSize());
            setLocation(x, y);

        }
    }
}

Le problème "majeur" de cette approche est que chaque Ball a son propre Thread. Cela va manger dans vos ressources de systèmes très vite que vous à l'échelle le nombre de balles...

Une approche différente

Comme commencé par l'aéroglisseur, vous feriez mieux de créer un conteneur dans lequel les balles ne sont pas des composants mais des concepts "virtuels" d'une balle, contenant suffisamment d'informations pour permettre de les faire rebondir sur les murs...

entrez la description de l'image ici

public class SimpleBalls {

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

    public SimpleBalls() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Spot");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                Balls balls = new Balls();
                frame.add(balls);
                frame.setSize(400, 400);
                frame.setVisible(true);

                new Thread(new BounceEngine(balls)).start();

            }
        });
    }

    public static int random(int maxRange) {
        return (int) Math.round((Math.random() * maxRange));
    }

    public class Balls extends JPanel {

        private List<Ball> ballsUp;

        public Balls() {
            ballsUp = new ArrayList<Ball>(25);

            for (int index = 0; index < 10 + random(90); index++) {
                ballsUp.add(new Ball(new Color(random(255), random(255), random(255))));
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            for (Ball ball : ballsUp) {
                ball.paint(g2d);
            }
            g2d.dispose();
        }

        public List<Ball> getBalls() {
            return ballsUp;
        }
    }

    public class BounceEngine implements Runnable {

        private Balls parent;

        public BounceEngine(Balls parent) {
            this.parent = parent;
        }

        @Override
        public void run() {

            int width = getParent().getWidth();
            int height = getParent().getHeight();

            // Randomize the starting position...
            for (Ball ball : getParent().getBalls()) {
                int x = random(width);
                int y = random(height);

                Dimension size = ball.getSize();

                if (x + size.width > width) {
                    x = width - size.width;
                }
                if (y + size.height > height) {
                    y = height - size.height;
                }

                ball.setLocation(new Point(x, y));

            }

            while (getParent().isVisible()) {

                // Repaint the balls pen...
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        getParent().repaint();
                    }
                });

                // This is a little dangrous, as it's possible
                // for a repaint to occur while we're updating...
                for (Ball ball : getParent().getBalls()) {
                    move(ball);
                }

                // Some small delay...
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                }

            }

        }

        public Balls getParent() {
            return parent;
        }

        public void move(Ball ball) {

            Point p = ball.getLocation();
            Point speed = ball.getSpeed();
            Dimension size = ball.getSize();

            int vx = speed.x;
            int vy = speed.y;

            int x = p.x;
            int y = p.y;

            if (x + vx < 0 || x + size.width + vx > getParent().getWidth()) {
                vx *= -1;
            }
            if (y + vy < 0 || y + size.height + vy > getParent().getHeight()) {
                vy *= -1;
            }
            x += vx;
            y += vy;

            ball.setSpeed(new Point(vx, vy));
            ball.setLocation(new Point(x, y));

        }
    }

    public class Ball {

        private Color color;
        private Point location;
        private Dimension size;
        private Point speed;

        public Ball(Color color) {

            setColor(color);

            speed = new Point(10 - random(20), 10 - random(20));
            size = new Dimension(30, 30);

        }

        public Dimension getSize() {
            return size;
        }

        public void setColor(Color color) {
            this.color = color;
        }

        public void setLocation(Point location) {
            this.location = location;
        }

        public Color getColor() {
            return color;
        }

        public Point getLocation() {
            return location;
        }

        public Point getSpeed() {
            return speed;
        }

        public void setSpeed(Point speed) {
            this.speed = speed;
        }

        protected void paint(Graphics2D g2d) {

            Point p = getLocation();
            if (p != null) {
                g2d.setColor(getColor());
                Dimension size = getSize();
                g2d.fillOval(p.x, p.y, size.width, size.height);
            }

        }
    }
}

Parce que cela est piloté par un seul thread, il est beaucoup plus évolutif.

Vous pouvez également consulter les images ne sont pas chargement qui est une question similaire ;)

 24
Author: MadProgrammer, 2017-05-23 12:10:11

Vous devez utiliser deux classes complètement distinctes ici-une pour BallContainer qui étend JPanel et est le composant qui dessine les Balles, et une autre pour Ball qui n'étend rien mais contient plutôt les coordonnées et la couleur d'une Balle. BallContainer devrait hodl a List<Ball> qu'il parcourt quand il les déplace et quand il les peint.

 8
Author: Hovercraft Full Of Eels, 2012-10-23 02:39:32

Ce que vous devez faire est d augmenter votre paintComponent méthode.

Au lieu de simplement dessiner une balle, vous devez les parcourir toutes et dessiner chacune.

Exemple:

protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D)g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    for (Ball b: balls) {
        g.setColor(color);
        g.fillOval(x,y,30,30); //adds color to circle
        g.setColor(Color.black);
        g2.drawOval(x,y,30,30); //draws circle
    }
}
 4
Author: jjnguy, 2018-02-22 03:12:04
package BouncingBallApp.src.copy;
import java.awt.*;


public class Ball {
    private Point location;
    private int radius;
    private Color color;
    private int dx, dy;
    //private Color[] ballArr;

    public Ball(Point l, int r, Color c){
        location = l;
        radius = r;
        color = c;
    }

    public Ball(Point l, int r){
        location = l;
        radius = r;
        color = Color.RED;

    }

    public Point getLocation() {
        return location;
    }

    public void setLocation(Point location) {
        this.location = location;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;

    }

    public void setMotion(int dx, int dy){
        this.dx = dx;
        this.dy = dy;
    }

    public void move(){
        location.translate(dx, dy);
    }

    public void moveTo(int x, int y){
        location.move(x, y);
    }

    public void paint (Graphics g) {
        g.setColor (color);
        g.fillOval (location.x-radius, location.y-radius, 2*radius, 2*radius);
    }

    public void reclectHoriz() {
        dy = -dy;       
    }   

    public void reclectVert() {
        dx = -dx;       
    }
}







package BouncingBallApp.src.copy;

public class MyApp {

    public static void main(String[] args) {
        MyFrame frm = new MyFrame(10);
        frm.setVisible(true);           

        for (int i=0; i<1000; i++){
            frm.stepTheBall();
        }
    }
}





package BouncingBallApp.src.copy;


import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;

import javax.swing.JFrame;


public class MyFrame extends JFrame {
    public final int FRAMEWIDTH = 600;
    public final int FRAMEHEIGHT = 400;

    private Ball[] ballArr;

    private Random random =new Random ();
    private Color[] colors={Color.RED,Color.blue,Color.yellow}; 
    private int ballCnt;

    public MyFrame(int ballCnt){
        super();
        setSize(FRAMEWIDTH, FRAMEHEIGHT);
        setTitle("My Bouncing Ball Application");

        ballArr = new Ball[ballCnt];
        this.ballCnt = ballCnt;
         int c;

        for (int i=0; i < ballCnt; i++){
            int bcn =random.nextInt(colors.length);
            Color ballcolor=colors[bcn];
            ballArr[i] = new Ball(new Point(50,50),c=(int) (Math.random()*10+3)%8,ballcolor);


            int ddx = (int) (Math.random()*10+2)%8;
            int ddy = (int) (Math.random()*10+2)%8;         
            ballArr[i].setMotion(ddx, ddy); 
            //c++;
        }
    }

    public void paint(Graphics g){
        super.paint(g);
        for (int i=0; i < ballCnt; i++){
            ballArr[i].paint(g);    
        }
    }

    public void stepTheBall(){
        for (int i=0; i < ballCnt; i++){        
            ballArr[i].move();

            Point loc = ballArr[i].getLocation();

            if (loc.x < ballArr[i].getRadius() ||
                loc.x > FRAMEWIDTH-ballArr[i].getRadius()){
                ballArr[i].reclectVert();
            }

            if (loc.y < ballArr[i].getRadius() ||
                    loc.y > FRAMEHEIGHT-ballArr[i].getRadius()){
                ballArr[i].reclectHoriz();
            }
        }   
        repaint();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
 -1
Author: user3478942, 2014-03-30 19:57:59