Java弹跳球 [英] Java Bouncing Ball

查看:37
本文介绍了Java弹跳球的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个 Java 应用程序,它在屏幕上绘制多个从框架边缘反弹的球.我可以成功地画一个球.但是,当我添加第二个球时,它会覆盖我绘制的初始球.代码是:

I am trying to write a Java application which draws multiple balls on screen which bounce off of the edges of the frame. I can successfully draw one ball. However when I add the second ball it overwrites the initial ball that I have drawn. The code is:

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

我想创建一个球列表,然后循环绘制每个球,但我仍然无法将两个球添加到内容窗格中.

I wanted to create a List of balls and then cycle through drawing each of the balls but I'm still having trouble adding both balls to the Content Pane.

感谢您的帮助.

推荐答案

以你目前的方法...

  • 我看到的主要问题是您将两个不透明的组件放在彼此的顶部...实际上您可能会发现您正在绕过其中一个组件...
  • 您应该使用 null 布局管理器,否则它将接管并按照它认为合适的方式布局您的球.
  • 您需要确保控制球窗格的大小和位置.这意味着您已经接管了布局经理的角色...
  • 您需要随机化球的速度和位置,以减少它们从同一位置开始并在同一位置移动的机会......
  • 仅在 EDT 上下文中更新 Ball.
  • 您实际上并不需要 X/Y 值,您可以使用面板.
  • With your current approach...

    • The main problem I can see is that you are placing two opaque components on top of each other...actually you may find you're circumventing one of them for the other...
    • You should be using a null layout manager, otherwise it will take over and layout your balls as it sees fit.
    • You need to ensure that you are controlling the size and location of the ball pane. This means you've taken over the role as the layout manager...
    • You need to randomize the speed and location of the balls to give them less chances of starting in the same location and moving in the same location...
    • Only update the Ball within the context of the EDT.
    • You don't really need the X/Y values, you can use the panels.
    • .

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

      这种方法的主要"问题是每个Ball 都有自己的Thread.当你增加球的数量时,这会很快消耗你的系统资源......

      The "major" problem with this approach, is each Ball has it's own Thread. This is going to eat into your systems resources real quick as you scale the number of balls up...

      从 Hovercraft 开始,您最好为球创建一个容器,其中球不是组件,而是球的虚拟"概念,包含足够的信息,可以将它们弹开墙壁...

      As started by Hovercraft, you're better off creating a container for the balls to live in, where the balls are not components but are "virtual" concepts of a ball, containing enough information to make it possible to bounce them off the walls...

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

      因为它是由单个线程驱动的,所以可扩展性更强.

      Because this is driven by a single thread, it is much more scalable.

      您还可以查看图片未加载是一个类似的问题;)

      You can also check out the images are not loading which is a similar question ;)

      这篇关于Java弹跳球的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆