2013-02-14 5 views
3

У меня проблема с моей текущей анимацией, которую я запускаю с помощью Java Swing. Это моделирование дискретных событий, и симуляция на основе текста работает нормально, у меня просто проблемы с подключением имитации к графическому интерфейсу.Swing анимация работает очень медленно

Для этого примера у меня будет моделировано 10 автомобилей. Автомобили представлены JPanels, о которых я расскажу в несколько мгновений.

Так что рассмотрите событие process_car_arrival. Каждый раз, когда это событие запланировано на выполнение, я добавляю объект Car к ArrayList под названием cars в моем классе Model. Car класс имеет следующие соответствующие атрибуты:

Point currentPos; // The current position, initialized in another method when knowing route. 
double speed; // giving the speed any value still causes the same problem but I have 5 atm. 
RouteType route; // for this example I only consider one simple route 

Кроме того, он имеет следующий метод move():

switch (this.route) { 
    case EAST: 
     this.currentPos.x -= speed; 
     return this.currentPos; 
. 
. 
. 
//only above is relevant in this example 

Это все хорошо. так что теоретически машина проходит по прямой дороге с востока на запад, поскольку я просто вызываю метод move() для каждого автомобиля, который я хочу переместить.

Возврат к событию process_car_arrival. После добавления объекта Car он вызывает метод addCarToEast() в классе View. Это добавляет JPanel в начале дороги, идущей с востока на запад.

Переход к View класса теперь у меня есть ** отдельный ** нить, который делает (метод вводного()) следующее:

@Override 
    public void run() { 
     while (true) { 
      try { 
       Thread.sleep(30); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      if (!cars.isEmpty()) { 

       cars.get(i).setLocation(
         new Point(getModel.getCars().get(i).move())); 

       if (i == cars.size() - 1) { 
        i = 0; 
       } else { 
        i++; 
       } 
      } 
     } 
    } 

выше делает движение автомобиля с востока на запад гладко первый. Но после того, как 3-4 машины двигаются, он просто заканчивается Чрезвычайно медленным, и когда у меня 10 автомобилей, они просто заканчиваются очень мало.

Просто чтобы прояснить, в данный момент в Model классе есть более ArrayList из Car объектов, и в View классе есть также ArrayList из JPanel объектов, представляющих автомобили. Я пытаюсь сопоставить объекты Car с JPanels, но я, очевидно, выполняю работу.

Я подозреваю, что я делаю что-то безумно неэффективное, но я не знаю, что. Сначала я думал, что, возможно, он обращается к ArrayList так, что, я думаю, сделает его очень медленным.

Любые указатели на то, что я могу изменить, чтобы он работал плавно?

+1

Моей первая забота оказывается обновление элементов пользовательского интерфейса из-за пределы события Диспетчерский поток. Это опасно и крайне нецелесообразно. Для получения дополнительной информации просмотрите [Параллелизм в Swing] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html). Второй вопрос, который у меня есть, это недостаточно, чтобы продолжать. Можете ли вы создать простой рабочий пример? Не нужно иметь изображения для автомобиля, достаточно простого прямоугольного представления. – MadProgrammer

+1

Наверх того, что сказал MadProgrammer, другой красный флаг - это то, что вы создаете отдельные JPanels. Это было некоторое время, так как я сделал что-то графическое, но я думаю, что вы должны использовать 2D-библиотеку и не перемещать «n» число JPanels. – Joe

+0

@MadProgrammer Я просто работаю по ссылке, которую вы мне дали, и пытаюсь понять, могу ли я что-нибудь поймать. Вернусь позже к простому рабочему примеру, если я не смогу заставить его работать. – DSF

ответ

11

Основываясь на этом предыдущем answer, приведенный ниже пример моделирует флот из трех кабин, перемещающихся случайным образом на прямоугольной сетке. A javax.swing.Timer управляет анимацией с частотой 5 Гц. Модель и представление тесно связаны в CabPanel, но анимация может предоставить некоторые полезные сведения. В частности, вы можете увеличить количество кабин или снизить задержку таймера.

image

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.RenderingHints; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.text.DecimalFormat; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 
import javax.swing.JButton; 
import javax.swing.JComboBox; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

/** 
* @see https://stackoverflow.com/a/14887457/230513 
* @see https://stackoverflow.com/questions/5617027 
*/ 

public class FleetPanel extends JPanel { 

    private static final Random random = new Random(); 
    private final MapPanel map = new MapPanel(); 
    private final JPanel control = new JPanel(); 
    private final List<CabPanel> fleet = new ArrayList<CabPanel>(); 
    private final Timer timer = new Timer(200, null); 

    public FleetPanel() { 
     super(new BorderLayout()); 
     fleet.add(new CabPanel("Cab #1", Hue.Cyan)); 
     fleet.add(new CabPanel("Cab #2", Hue.Magenta)); 
     fleet.add(new CabPanel("Cab #3", Hue.Yellow)); 
     control.setLayout(new GridLayout(0, 1)); 
     for (CabPanel cp : fleet) { 
      control.add(cp); 
      timer.addActionListener(cp.listener); 
     } 
     this.add(map, BorderLayout.CENTER); 
     this.add(control, BorderLayout.SOUTH); 
    } 

    public void start() { 
     timer.start(); 
    } 

    private class CabPanel extends JPanel { 

     private static final String format = "000000"; 
     private final DecimalFormat df = new DecimalFormat(format); 
     private JLabel name = new JLabel("", JLabel.CENTER); 
     private Point point = new Point(); 
     private JLabel position = new JLabel(toString(point), JLabel.CENTER); 
     private int blocks; 
     private JLabel odometer = new JLabel(df.format(0), JLabel.CENTER); 
     private final JComboBox colorBox = new JComboBox(); 
     private final JButton reset = new JButton("Reset"); 
     private final ActionListener listener = new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       int ds = random.nextInt(3) - 1; 
       if (random.nextBoolean()) { 
        point.x += ds; 
       } else { 
        point.y += ds; 
       } 
       blocks += Math.abs(ds); 
       update(); 
      } 
     }; 

     public CabPanel(String s, Hue hue) { 
      super(new GridLayout(1, 0)); 
      name.setText(s); 
      this.setBackground(hue.getColor()); 
      this.add(map, BorderLayout.CENTER); 
      for (Hue h : Hue.values()) { 
       colorBox.addItem(h); 
      } 
      colorBox.setSelectedIndex(hue.ordinal()); 
      colorBox.addActionListener(new ActionListener() { 

       @Override 
       public void actionPerformed(ActionEvent e) { 
        Hue h = (Hue) colorBox.getSelectedItem(); 
        CabPanel.this.setBackground(h.getColor()); 
        update(); 
       } 
      }); 
      reset.addActionListener(new ActionListener() { 

       @Override 
       public void actionPerformed(ActionEvent e) { 
        point.setLocation(0, 0); 
        blocks = 0; 
        update(); 
       } 
      }); 
      this.add(name); 
      this.add(odometer); 
      this.add(position); 
      this.add(colorBox); 
      this.add(reset); 
     } 

     private void update() { 
      position.setText(CabPanel.this.toString(point)); 
      odometer.setText(df.format(blocks)); 
      map.repaint(); 
     } 

     private String toString(Point p) { 
      StringBuilder sb = new StringBuilder(); 
      sb.append(Math.abs(p.x)); 
      sb.append(p.x < 0 ? " W" : " E"); 
      sb.append(", "); 
      sb.append(Math.abs(p.y)); 
      sb.append(p.y < 0 ? " N" : " S"); 
      return sb.toString(); 
     } 
    } 

    private class MapPanel extends JPanel { 

     private static final int SIZE = 16; 

     public MapPanel() { 
      this.setPreferredSize(new Dimension(32 * SIZE, 32 * SIZE)); 
      this.setBackground(Color.lightGray); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g; 
      g2d.setRenderingHint(
       RenderingHints.KEY_ANTIALIASING, 
       RenderingHints.VALUE_ANTIALIAS_ON); 
      int w = this.getWidth(); 
      int h = this.getHeight(); 
      g2d.setColor(Color.gray); 
      for (int col = SIZE; col <= w; col += SIZE) { 
       g2d.drawLine(col, 0, col, h); 
      } 
      for (int row = SIZE; row <= h; row += SIZE) { 
       g2d.drawLine(0, row, w, row); 
      } 

      for (CabPanel cp : fleet) { 
       Point p = cp.point; 
       int x = SIZE * (p.x + w/2/SIZE) - SIZE/2; 
       int y = SIZE * (p.y + h/2/SIZE) - SIZE/2; 
       g2d.setColor(cp.getBackground()); 
       g2d.fillOval(x, y, SIZE, SIZE); 
      } 
     } 
    } 

    public enum Hue { 

     Cyan(Color.cyan), Magenta(Color.magenta), Yellow(Color.yellow), 
     Red(Color.red), Green(Color.green), Blue(Color.blue), 
     Orange(Color.orange), Pink(Color.pink); 
     private final Color color; 

     private Hue(Color color) { 
      this.color = color; 
     } 

     public Color getColor() { 
      return color; 
     } 
    } 

    private static void display() { 
     JFrame f = new JFrame("Dispatch"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     FleetPanel fp = new FleetPanel(); 
     f.add(fp); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
     fp.start(); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       display(); 
      } 
     }); 
    } 
} 
+0

См. Также этот MVC [пример] (http://stackoverflow.com/a/3072979/230513). – trashgod

+0

Спасибо, сэр :) Отличное понимание. Выучил гораздо больше от чтения своего кода за 1 час, чем я всю ночь провел в отчаянии! – DSF

+0

+1 очень приятно ... –

5

Я не мог сопротивляться ...

enter image description here

Я получил 500 автомобилей, работающих на экране с немного замедлить (это не самый быстрый ... 200-300 было довольно хорошо ...

Это использует панели для представления каждое транспортное средство. Если вы хотите, чтобы получить более высокую производительность, ваш, вероятно, нужно посмотреть на использование подкладочного буфера какого-то.

public class TestAnimation10 { 

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

    public TestAnimation10() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (Exception ex) { 
       } 

       final TrackPane trackPane = new TrackPane(); 
       JSlider slider = new JSlider(1, 500); 
       slider.addChangeListener(new ChangeListener() { 
        @Override 
        public void stateChanged(ChangeEvent e) { 
         trackPane.setCongestion(((JSlider)e.getSource()).getValue()); 
        } 
       }); 
       slider.setValue(5); 

       JFrame frame = new JFrame("Test"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(trackPane); 
       frame.add(slider, BorderLayout.SOUTH); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 

      } 
     }); 
    } 

    public class TrackPane extends JPanel { 

     private List<Car> cars; 
     private int maxCars = 1; 

     private List<Point2D[]> points; 

     private Ellipse2D areaOfEffect; 

     public TrackPane() { 

      points = new ArrayList<>(25); 

      cars = new ArrayList<>(25); 
      setLayout(null); 

      Timer timer = new Timer(40, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 

        Rectangle bounds = areaOfEffect.getBounds(); 
        List<Car> tmp = new ArrayList<>(cars); 
        for (Car car : tmp) { 
         car.move(); 
         if (!bounds.intersects(car.getBounds())) { 
          remove(car); 
          cars.remove(car); 
         } 
        } 
        updatePool(); 
        repaint(); 
       } 
      }); 

      timer.setRepeats(true); 
      timer.setCoalesce(true); 
      timer.start(); 

      updateAreaOfEffect(); 
     } 

     protected void updateAreaOfEffect() { 
      double radius = Math.max(getWidth(), getHeight()) * 1.5d; 
      double x = (getWidth() - radius)/2d; 
      double y = (getHeight() - radius)/2d; 
      areaOfEffect = new Ellipse2D.Double(x, y, radius, radius); 
     } 

     @Override 
     public void invalidate() { 
      super.invalidate(); 
      updateAreaOfEffect(); 
     } 

     protected void updatePool() { 
      while (cars.size() < maxCars) { 
//   if (cars.size() < maxCars) { 
       Car car = new Car(); 
       double direction = car.getDirection(); 
       double startAngle = direction - 180; 

       double radius = areaOfEffect.getWidth(); 
       Point2D startPoint = getPointAt(radius, startAngle); 

       int cx = getWidth()/2; 
       int cy = getHeight()/2; 

       double x = cx + (startPoint.getX() - car.getWidth()/2); 
       double y = cy + (startPoint.getY() - car.getHeight()/2); 
       car.setLocation((int)x, (int)y); 

       Point2D targetPoint = getPointAt(radius, direction); 

       points.add(new Point2D[]{startPoint, targetPoint}); 

       add(car); 

       cars.add(car); 
      } 
     } 

     @Override 
     public void paint(Graphics g) { 
      super.paint(g); 
      Font font = g.getFont(); 
      font = font.deriveFont(Font.BOLD, 48f); 
      FontMetrics fm = g.getFontMetrics(font); 
      g.setFont(font); 
      g.setColor(Color.RED); 
      String text = Integer.toString(maxCars); 
      int x = getWidth() - fm.stringWidth(text); 
      int y = getHeight() - fm.getHeight() + fm.getAscent(); 
      g.drawString(text, x, y); 
      text = Integer.toString(getComponentCount()); 
      x = getWidth() - fm.stringWidth(text); 
      y -= fm.getHeight(); 
      g.drawString(text, x, y); 
      text = Integer.toString(cars.size()); 
      x = getWidth() - fm.stringWidth(text); 
      y -= fm.getHeight(); 
      g.drawString(text, x, y); 
     } 

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

     public void setCongestion(int value) { 
      maxCars = value; 
     } 
    } 

    protected static Point2D getPointAt(double radius, double angle) { 

     double x = Math.round(radius/2d); 
     double y = Math.round(radius/2d); 

     double rads = Math.toRadians(-angle); 

     double fullLength = Math.round((radius/2d)); 

     double xPosy = (Math.cos(rads) * fullLength); 
     double yPosy = (Math.sin(rads) * fullLength); 

     return new Point2D.Double(xPosy, yPosy); 

    } 

    public class Car extends JPanel { 

     private double direction; 
     private double speed; 
     private BufferedImage background; 

     public Car() { 
      setOpaque(false); 
      direction = Math.random() * 360; 
      speed = 5 + (Math.random() * 10); 
      int image = 1 + (int) Math.round(Math.random() * 5); 
      try { 
       String name = "/Car0" + image + ".png"; 
       background = ImageIO.read(getClass().getResource(name)); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
      setSize(getPreferredSize()); 
//   setBorder(new LineBorder(Color.RED)); 
     } 

     public void setDirection(double direction) { 
      this.direction = direction; 
      revalidate(); 
      repaint(); 
     } 

     public double getDirection() { 
      return direction; 
     } 

     public void move() { 
      Point at = getLocation(); 
      at.x += (int)(speed * Math.cos(Math.toRadians(-direction))); 
      at.y += (int)(speed * Math.sin(Math.toRadians(-direction))); 
      setLocation(at); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      Dimension size = super.getPreferredSize(); 
      if (background != null) { 
       double radian = Math.toRadians(direction); 
       double sin = Math.abs(Math.sin(radian)), cos = Math.abs(Math.cos(radian)); 
       int w = background.getWidth(), h = background.getHeight(); 
       int neww = (int) Math.floor(w * cos + h * sin); 
       int newh = (int) Math.floor(h * cos + w * sin); 
       size = new Dimension(neww, newh); 
      } 
      return size; 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      int x = (getWidth() - background.getWidth())/2; 
      int y = (getHeight() - background.getHeight())/2; 
      g2d.rotate(Math.toRadians(-(direction + 180)), getWidth()/2, getHeight()/2); 
      g2d.drawImage(background, x, y, this); 
      g2d.dispose(); 

//   Debug graphics... 
//   int cx = getWidth()/2; 
//   int cy = getHeight()/2; 
// 
//   g2d = (Graphics2D) g.create(); 
//   g2d.setColor(Color.BLUE); 
//   double radius = Math.min(getWidth(), getHeight()); 
//   Point2D pointAt = getPointAt(radius, direction); 
//   g2d.draw(new Ellipse2D.Double(cx - (radius/2d), cy - (radius/2d), radius, radius)); 
//    
//   double xo = cx; 
//   double yo = cy; 
//   double xPos = cx + pointAt.getX(); 
//   double yPos = cy + pointAt.getY(); 
//    
//   g2d.draw(new Line2D.Double(xo, yo, xPos, yPos)); 
//   g2d.draw(new Ellipse2D.Double(xPos - 2, yPos - 2, 4, 4)); 
//   g2d.dispose(); 
     } 
    } 
} 

Обновленных с оптимизированной версией

Я немного оптимизировал код с созданием объектов автомобиля (там все еще есть возможность для улучшения) и поработал графический выход (он выглядел лучше).

В принципе, теперь, когда автомобиль выходит из экрана, он помещается в бассейн. Когда требуется другой автомобиль, если это возможно, его вытаскивают из бассейна, иначе производится новый автомобиль. Это уменьшило накладные расходы на создание и уничтожение многих (релятивно) короткоживущих объектов, что делает использование памяти более стабильным.

На моем экране с разрешением экрана 2560x1600 (работает максимально) я смог одновременно запустить 4500 автомобилей. Как только создание объекта было уменьшено, он работал относительно плавно (он никогда не будет работать так же хорошо, как и 10, но он не страдал от значительного снижения скорости).

public class TestAnimation10 { 

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

    public TestAnimation10() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (Exception ex) { 
       } 

       final TrackPane trackPane = new TrackPane(); 
       JSlider slider = new JSlider(1, 5000); 
       slider.addChangeListener(new ChangeListener() { 
        @Override 
        public void stateChanged(ChangeEvent e) { 
         trackPane.setCongestion(((JSlider) e.getSource()).getValue()); 
        } 
       }); 
       slider.setValue(5); 

       JFrame frame = new JFrame("Test"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(trackPane); 
       frame.add(slider, BorderLayout.SOUTH); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 

      } 
     }); 
    } 

    public class TrackPane extends JPanel { 

     private List<Car> activeCarList; 
     private List<Car> carPool; 
     private int maxCars = 1; 
     private List<Point2D[]> points; 
     private Ellipse2D areaOfEffect; 

     public TrackPane() { 

      points = new ArrayList<>(25); 

      activeCarList = new ArrayList<>(25); 
      carPool = new ArrayList<>(25); 
      setLayout(null); 

      Timer timer = new Timer(40, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 

        Rectangle bounds = areaOfEffect.getBounds(); 
        List<Car> tmp = new ArrayList<>(activeCarList); 
        for (Car car : tmp) { 
         car.move(); 
         if (!bounds.intersects(car.getBounds())) { 
          remove(car); 
          activeCarList.remove(car); 
          carPool.add(car); 
         } 
        } 
        updatePool(); 
        repaint(); 
       } 
      }); 

      timer.setRepeats(true); 
      timer.setCoalesce(true); 
      timer.start(); 

      updateAreaOfEffect(); 
     } 

     protected void updateAreaOfEffect() { 
      double radius = Math.max(getWidth(), getHeight()) * 1.5d; 
      double x = (getWidth() - radius)/2d; 
      double y = (getHeight() - radius)/2d; 
      areaOfEffect = new Ellipse2D.Double(x, y, radius, radius); 
     } 

     @Override 
     public void invalidate() { 
//   super.invalidate(); 
      updateAreaOfEffect(); 
     } 

     protected void updatePool() { 
      if (activeCarList.size() < maxCars) { 
       int count = Math.min(maxCars - activeCarList.size(), 10); 
       for (int index = 0; index < count; index++) { 
        Car car = null; 

        if (carPool.isEmpty()) { 
         car = new Car(); 
        } else { 
         car = carPool.remove(0); 
        } 

        double direction = car.getDirection(); 
        double startAngle = direction - 180; 

        double radius = areaOfEffect.getWidth(); 
        Point2D startPoint = getPointAt(radius, startAngle); 

        int cx = getWidth()/2; 
        int cy = getHeight()/2; 

        double x = cx + (startPoint.getX() - car.getWidth()/2); 
        double y = cy + (startPoint.getY() - car.getHeight()/2); 
        car.setLocation((int) x, (int) y); 

        Point2D targetPoint = getPointAt(radius, direction); 

        points.add(new Point2D[]{startPoint, targetPoint}); 

        add(car); 

        activeCarList.add(car); 
       } 
      } 
     } 

     @Override 
     public void paint(Graphics g) { 
      super.paint(g); 
      Font font = g.getFont(); 
      font = font.deriveFont(Font.BOLD, 48f); 
      FontMetrics fm = g.getFontMetrics(font); 
      g.setFont(font); 
      g.setColor(Color.RED); 
      String text = Integer.toString(maxCars); 
      int x = getWidth() - fm.stringWidth(text); 
      int y = getHeight() - fm.getHeight() + fm.getAscent(); 
      g.drawString(text, x, y); 
      text = Integer.toString(getComponentCount()); 
      x = getWidth() - fm.stringWidth(text); 
      y -= fm.getHeight(); 
      g.drawString(text, x, y); 
      text = Integer.toString(activeCarList.size()); 
      x = getWidth() - fm.stringWidth(text); 
      y -= fm.getHeight(); 
      g.drawString(text, x, y); 
      text = Integer.toString(carPool.size()); 
      x = getWidth() - fm.stringWidth(text); 
      y -= fm.getHeight(); 
      g.drawString(text, x, y); 
     } 

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

     public void setCongestion(int value) { 
      maxCars = value; 
     } 

     @Override 
     public void validate() { 
     } 

     @Override 
     public void revalidate() { 
     } 

//  @Override 
//  public void repaint(long tm, int x, int y, int width, int height) { 
//  } 
// 
//  @Override 
//  public void repaint(Rectangle r) { 
//  } 
//  public void repaint() { 
//  } 
     @Override 
     protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { 
      System.out.println(propertyName); 
//   // Strings get interned... 
//   if (propertyName == "text" 
//       || propertyName == "labelFor" 
//       || propertyName == "displayedMnemonic" 
//       || ((propertyName == "font" || propertyName == "foreground") 
//       && oldValue != newValue 
//       && getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) { 
// 
//    super.firePropertyChange(propertyName, oldValue, newValue); 
//   } 
     } 

     @Override 
     public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { 
     } 
    } 

    protected static Point2D getPointAt(double radius, double angle) { 

     double x = Math.round(radius/2d); 
     double y = Math.round(radius/2d); 

     double rads = Math.toRadians(-angle); 

     double fullLength = Math.round((radius/2d)); 

     double xPosy = (Math.cos(rads) * fullLength); 
     double yPosy = (Math.sin(rads) * fullLength); 

     return new Point2D.Double(xPosy, yPosy); 

    } 

    public class Car extends JPanel { 

     private double direction; 
     private double speed; 
     private BufferedImage background; 

     public Car() { 
      setOpaque(false); 
      direction = Math.random() * 360; 
      speed = 5 + (Math.random() * 10); 
      int image = 1 + (int) Math.round(Math.random() * 5); 
      try { 
       String name = "/Car0" + image + ".png"; 
       background = ImageIO.read(getClass().getResource(name)); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
      setSize(getPreferredSize()); 
//   setBorder(new LineBorder(Color.RED)); 
     } 

     public void setDirection(double direction) { 
      this.direction = direction; 
      revalidate(); 
      repaint(); 
     } 

     public double getDirection() { 
      return direction; 
     } 

     public void move() { 
      Point at = getLocation(); 
      at.x += (int) (speed * Math.cos(Math.toRadians(-direction))); 
      at.y += (int) (speed * Math.sin(Math.toRadians(-direction))); 
      setLocation(at); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      Dimension size = super.getPreferredSize(); 
      if (background != null) { 
       double radian = Math.toRadians(direction); 
       double sin = Math.abs(Math.sin(radian)), cos = Math.abs(Math.cos(radian)); 
       int w = background.getWidth(), h = background.getHeight(); 
       int neww = (int) Math.floor(w * cos + h * sin); 
       int newh = (int) Math.floor(h * cos + w * sin); 
       size = new Dimension(neww, newh); 
      } 
      return size; 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
      g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 
      g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
      g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
      g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 
      int x = (getWidth() - background.getWidth())/2; 
      int y = (getHeight() - background.getHeight())/2; 
      g2d.rotate(Math.toRadians(-(direction + 180)), getWidth()/2, getHeight()/2); 
      g2d.drawImage(background, x, y, this); 
      g2d.dispose(); 

//   Debug graphics... 
//   int cx = getWidth()/2; 
//   int cy = getHeight()/2; 
// 
//   g2d = (Graphics2D) g.create(); 
//   g2d.setColor(Color.BLUE); 
//   double radius = Math.min(getWidth(), getHeight()); 
//   Point2D pointAt = getPointAt(radius, direction); 
//   g2d.draw(new Ellipse2D.Double(cx - (radius/2d), cy - (radius/2d), radius, radius)); 
//    
//   double xo = cx; 
//   double yo = cy; 
//   double xPos = cx + pointAt.getX(); 
//   double yPos = cy + pointAt.getY(); 
//    
//   g2d.draw(new Line2D.Double(xo, yo, xPos, yPos)); 
//   g2d.draw(new Ellipse2D.Double(xPos - 2, yPos - 2, 4, 4)); 
//   g2d.dispose(); 
     } 

     @Override 
     public void invalidate() { 
     } 

     @Override 
     public void validate() { 
     } 

     @Override 
     public void revalidate() { 
     } 

     @Override 
     public void repaint(long tm, int x, int y, int width, int height) { 
     } 

     @Override 
     public void repaint(Rectangle r) { 
     } 

     @Override 
     public void repaint() { 
     } 

     @Override 
     protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { 
//   System.out.println(propertyName); 
//   // Strings get interned... 
//   if (propertyName == "text" 
//       || propertyName == "labelFor" 
//       || propertyName == "displayedMnemonic" 
//       || ((propertyName == "font" || propertyName == "foreground") 
//       && oldValue != newValue 
//       && getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) { 
// 
//    super.firePropertyChange(propertyName, oldValue, newValue); 
//   } 
     } 

     @Override 
     public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { 
     } 
    } 
} 

пс - я должен добавить 1- Мой 10-месячный любил его 2- Это напомнило мне о пробеге работать: P

+0

+1 fun; также занимательный с ['RobotChase'] (http: // sourceforge.net/p/robotchase/code/67/tree/trunk/images /) cast members. – trashgod

+0

@MadProgrammer - Спасибо за это. Изучит ваш код и посмотрит, что я могу извлечь из него (возможно, много!). Просто из любопытства, как долго вы программируете в Swing? Я только что начал месяц назад, но считаю его ошеломляющим, поскольку существует так много разных способов делать что-то, а иногда трудно понять, что лучше всего и т. Д. Это просто проблема, которая у меня есть, или это вообще что-то новички опыт? Я надеюсь, что в такие дни я буду так же хорош, как программисты, как вы и trashgod, хотя кажется, что сейчас очень далеко! – DSF

+3

Я использую Java/Swing с Java 1.3, где-то около 1999 года. Проблема, с которой сталкивается каждый разработчик все время, на самом деле, я думаю, что чем больше вы знаете, тем хуже. Разница в том, что вы склонны к опыту, чтобы иметь возможность быстрее отказываться от определенных идей. Не бойтесь попробовать что-то и отказаться от него. Самое худшее, что вы можете сделать, это продолжить путь просто потому, что вы потратили на него столько времени. Если вы можете лучше, лучше начать снова – MadProgrammer

Смежные вопросы