Java Bouncing Ball

Sto cercando di scrivere un’applicazione Java che disegna più palline sullo schermo che rimbalzano sui bordi del fotogramma. Posso estrarre con successo una palla. Comunque quando aggiungo la seconda palla sovrascrive la palla iniziale che ho disegnato. Il codice è:

import java.awt.*; import javax.swing.*; import java.util.ArrayList; import java.util.List; public class Ball extends JPanel implements Runnable { List balls = new ArrayList(); 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  getWidth()) { vx *= -1; } if(y + 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(); } } 

Volevo creare un elenco di palline e quindi passare in rassegna il disegno di ciascuna pallina, ma ho ancora difficoltà ad aggiungere entrambe le sfere al riquadro del contenuto.

Grazie per qualsiasi aiuto.

Con il tuo attuale approccio …

  • Il problema principale che posso vedere è che stai mettendo due componenti opachi uno sopra l’altro … in realtà potresti scoprire che stai aggirando uno di questi per l’altro …
  • Dovresti usare un gestore di layout null , altrimenti prenderà il comando e imposterà le palle come meglio crede.
  • È necessario assicurarsi di controllare la dimensione e la posizione del riquadro della sfera. Ciò significa che hai assunto il ruolo di gestore del layout …
  • Hai bisogno di randomizzare la velocità e la posizione delle palle per dare loro meno possibilità di iniziare nella stessa posizione e muoversi nella stessa posizione …
  • Aggiorna la Ball nel contesto dell’EDT.
  • Non hai veramente bisogno dei valori X / Y, puoi usare i pannelli.

.

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

Il problema “principale” di questo approccio è che ogni Ball ha il proprio Thread . Questo andrà a finire nelle risorse del tuo sistema molto velocemente mentre riduci il numero di palle …

Un approccio diverso

Come iniziato da Hovercraft, è meglio creare un contenitore per le palle in cui vivere, in cui le palline non sono componenti ma sono concetti “virtuali” di una palla, contenenti informazioni sufficienti a consentire di rimbalzarli dalle pareti. ..

inserisci la descrizione dell'immagine qui

 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 ballsUp; public Balls() { ballsUp = new ArrayList(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 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 = px; int y = py; 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(px, py, size.width, size.height); } } } } 

Poiché questo è guidato da un singolo thread, è molto più scalabile.

Puoi anche controllare che le immagini non vengano caricate, che è una domanda simile;)

È necessario utilizzare due classi completamente distinte: una per BallContainer che estende JPanel ed è il componente che disegna le Balls, e un’altra per Ball che non estende nulla ma che mantiene le coordinate e il Colore di una palla. BallContainer dovrebbe tenere un List che itera attraverso quando li muove e quando li dipinge.

Quello che devi fare è aumentare il tuo metodo paintComponent .

Invece di disegnare solo una palla, devi farle scorrere tutte e disegnare ciascuna.

Esempio:

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