2012-11-22 23 views
6

Tôi đã viết một applet hệ thống hạt; hiện tại tôi đang tạo và vẽ riêng từng hạt. (Đây là mã)Vẽ nhiều hạt một cách hiệu quả

BufferedImage backbuffer; 
Graphics2D g2d; 

public void init(){ 
    backbuffer = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB); 
    g2d = backbuffer.createGraphics(); 
    setSize(WIDTH, HEIGHT); 

    //creates the particles 
    for (int i = 0; i < AMOUNTPARTICLES; i++) { 
     prtl[i] = new particleO(); 
     prtl[i].setX(rand.nextInt(STARTX)); 
     prtl[i].setY(rand.nextInt(STARTY)); 
     prtl[i].setVel(rand.nextInt(MAXSPEED)+1); 
     prtl[i].setFAngle(Math.toRadians(rand.nextInt(ANGLESPREAD))); 

     } 

    //other code 
} 



    public void update(Graphics g) {   

    g2d.setTransform(identity); 

    //set background 
    g2d.setPaint(BGCOLOUR); 
    g2d.fillRect(0,0,getSize().width,getSize().height); 
    drawp(); 
    paint(g);   
    } 


public void drawp() { 

    for (int n = 0; n < AMOUNTPARTICLES; n++) { 

    if (prtl[n].getAlive()==true){ 
      g2d.setTransform(identity); 
      g2d.translate(prtl[n].getX(), prtl[n].getY()); 
      g2d.setColor(prtl[n].getColor()); 

      g2d.fill(prtl[n].getShape()); 


      } 
    } 

} 

Đó là hiệu suất là không sao, tôi có thể nhận được ~ 40fps với 20.000 hạt (mặc dù, tôi có một máy tính xách tay đàng hoàng). Nhưng sau khi tôi thêm phát hiện va chạm (xem dưới đây), con số đó giảm mạnh xuống dưới 2000,

public void particleUpdate(){ 
for (int i = 0; i < AMOUNTPARTICLES; i++) { 
     //other update code (posx, posy, angle etc etc) 

      for (int j = 0; j < AMOUNTPARTICLES; j++) { 

       if (i!=j && prtl[j].getAlive()==true){ 

        if(hasCollided(i, j)){ 
         prtl[i].setcolor(Color.BLACK); 
         prtl[j].setcolor(Color.BLACK); 
    } 
      } 
    } 

public boolean hasCollided(int prt1, int prt2){ 

     double dx = prtl[prt1].getX() - prtl[prt2].getX(); 
     double dy = prtl[prt1].getY() - prtl[prt2].getY(); 
     int edges = prtl[prt1].getRadius() + prtl[prt2].getRadius(); 

     double distance = Math.sqrt((dx*dx) + (dy*dy)); 
     return (distance <= edges); 


    } 

Tôi đã tìm kiếm khá một chút cho một cách tốt hơn vẽ các hạt vào màn hình, nhưng các ví dụ hoặc nhầm lẫn tôi hoặc không được áp dụng.

Tôi đang thực hiện tải trọng tính toán của thuyền (quá nhiều). Nhưng tôi không thể nghĩ ra một cách khác để làm điều đó, đề xuất được hoan nghênh.

+0

http://stackoverflow.com/questions/13046033/an-efficient-way-to-simulate-many-particle-collisions –

+0

Đừng quên chấp nhận câu trả lời khi bạn đã quyết định cái nào giúp bạn nhiều nhất. – PearsonArtPhoto

Trả lời

5

Trước hết, thêm vào một cái gì đó giống như phát hiện va chạm luôn mất rất nhiều bộ nhớ. Tuy nhiên, chúng ta hãy nhìn vào thuật toán phát hiện va chạm của bạn

public void particleUpdate(){ 
for (int i = 0; i < AMOUNTPARTICLES; i++) { 
     //other update code (posx, posy, angle etc etc) 

      for (int j = 0; j < AMOUNTPARTICLES; j++) { 

       if (i!=j && prtl[j].getAlive()==true){ 

        if(hasCollided(i, j)){ 
         prtl[i].setcolor(Color.BLACK); 
         prtl[j].setcolor(Color.BLACK); 
       } 
      } 
    } 

Hãy giả vờ chỉ có 2 hạt, 1 và 2. Bạn sẽ kiểm tra, để 1,1 1,2 2,1 2,2

Sự thật là bạn chỉ thực sự cần kiểm tra 1 và 2 trong trường hợp này. Nếu 1 lượt truy cập 2, 2 cũng sẽ đạt 1. Vì vậy, thay đổi vòng lặp bỏ qua của bạn đã bỏ qua thử nghiệm trước đây và cùng một số cho vấn đề đó.

public void particleUpdate(){ 
for (int i = 0; i < AMOUNTPARTICLES; i++) { 
     //other update code (posx, posy, angle etc etc) 

      for (int j = i+1; j < AMOUNTPARTICLES; j++) { 

Một điều khác tôi nhận thấy là bạn thực hiện thao tác sqrt, nhưng chỉ để so sánh với số trông giống như số tĩnh. Nếu bạn loại bỏ điều đó, và so sánh nó với số bình phương, bạn sẽ nhận được một cải tiến lớn, đặc biệt là với một cái gì đó bạn làm rất nhiều.

double distance_squared = ((dx*dx) + (dy*dy)); 
    return (distance <= edges*edges); 

Tiếp tục tìm kiếm các cải tiến như thế này. Sau đó, bạn có thể cẩn thận xem xét các tùy chọn khác, như sử dụng một lớp khác nhau, luồng, vv, mà tất cả có thể cải thiện hệ thống. Nhưng hãy đảm bảo bạn tối ưu hóa mã nơi bạn có thể đầu tiên. Dưới đây là danh sách những thứ khác mà tôi sẽ thử, gần như theo thứ tự.

  1. Kiểm tra xem hạt i có còn sống hay không trước khi bạn tính toán bất kỳ thứ gì khác sau khi tôi xem.
  2. Thực hiện chuyển nhanh qua các cặp, thậm chí chỉ bận tâm kiểm tra chi tiết nếu chúng ở gần. Một cách đơn giản sẽ là phát hiện xem chúng có nằm trong kích thước x và y trước, trước khi thực hiện một thao tác sqrt. Luôn làm bài kiểm tra rẻ nhất trước, trước khi thực hiện những thử nghiệm phức tạp.
  3. Xem mã của bạn, để xem liệu bạn có thực sự sử dụng tất cả các giá trị được tính hay không hoặc bạn có thể giảm số lượng hoạt động bằng cách nào đó.
  4. Có lẽ bạn có thể nhóm hình ảnh một cách thường xuyên với một đột quỵ rộng, sau đó tinh chỉnh chỉ các đối tượng đã vượt qua cụm ban đầu trong một khoảng thời gian, sau đó thực hiện một thuật toán cụm rộng.
  5. Bạn có thể tạo luồng phát hiện xung đột. Tuy nhiên, nếu bạn định làm điều này, bạn chỉ nên kiểm tra chuỗi để xem có điều gì đó đã va chạm hay không, và sau khi tất cả các luồng đó được thực hiện, hãy cập nhật các đối tượng trên khung nhìn.
  6. Xem xét các kiến ​​trúc thay thế, điều này có thể giúp tăng tốc một số kiến ​​trúc.
+0

Cảm ơn rất nhiều, tôi đã suy nghĩ về một cái gì đó như thế (lồng nhau cho của) nhưng nó sẽ không đi ra khỏi đầu của tôi (+1) – user1159424

+0

Không có vấn đề. Tối ưu hóa các công cụ như thế này có lẽ là phần yêu thích của tôi về lập trình :-) – PearsonArtPhoto

+0

Ngoài ra, làm thế nào về việc kiểm tra các hạt đã di chuyển? Chỉ vẽ các hạt đã di chuyển từ khung cuối cùng. Cũng vậy với những va chạm; 2 hạt không di chuyển sẽ không va vào nhau. –

4

Tranh là một quá trình phức tạp và yêu cầu vẽ có thể được kích hoạt vì bất kỳ lý do nào, hệ điều hành có thể muốn cửa sổ cập nhật, người quản lý có thể muốn vẽ lại, người lập trình có thể muốn vẽ lại.

Cập nhật các hạt trong quy trình paint là ý tưởng tồi. Những gì bạn muốn làm là cập nhật các hạt trong một sợi riêng biệt trên một bộ đệm riêng biệt. Khi bạn đã sẵn sàng, hãy yêu cầu thành phần chịu trách nhiệm vẽ bộ đệm thực hiện một bản sao, chuyển một bản sao mới của bộ đệm để sơn lại (bạn không muốn vẽ trên bộ đệm bắt đầu được cập nhật lên màn hình, bạn ' sẽ kết thúc bằng sơn bẩn).

Thật khó để nói từ mã của bạn, nhưng có vẻ như bạn đang sử dụng java.awt.Applet, cá nhân, tôi sẽ nâng cấp lên javax.swing.JApplet.

Tôi muốn di chuyển bức tranh đến java.swing.JPanel. Các thành phần Swing cung cấp đệm đôi (cũng như các chiến lược đệm khác). Công việc duy nhất của bảng điều khiển này là vẽ một bộ đệm cho màn hình khi động cơ hạt có một khung mới.

Động cơ hạt chịu trách nhiệm cập nhật tất cả các hạt và vẽ các kết quả này vào bộ đệm sao lưu (BufferedImage), sau đó sẽ được chuyển tới bảng điều khiển và bảng điều khiển sẽ sao chép và lên lịch cập nhật.

Đu KHÔNG PHẢI LÀ AN TOÀN. Tức là, bạn không nên thực hiện thay đổi đối với giao diện người dùng từ bất kỳ chuỗi nào khác, sau đó là Chuỗi gửi sự kiện. Để kết thúc này, bạn có thể muốn đọc qua Concurrency in Swing cho các giải pháp để đồng bộ hóa bộ đệm tắt màn hình cho máy khách.

+0

+1 Vị trí đẹp: P – MadProgrammer

+0

Rất nhiều thông tin, công ty – user1159424

0

Bạn đang kiểm tra tất cả các xung đột với tất cả các hạt và đây là điều kiện tiên quyết, theo thứ tự của n^2 (2.000 hạt có nghĩa là 4.000.000 kết hợp, cho mỗi khung).

Vấn đề không phải là java mà là thuật toán. Phải có các lựa chọn tốt hơn, nhưng để bắt đầu với bạn có thể làm giảm sự so sánh; nếu bạn có tốc độ tối đa S và thời gian trong thế giới của bạn tăng thêm T, với T * S bạn nhận được khoảng cách tối đa D của một hạt có thể va chạm với hạt bạn đang xem xét. Giảm tìm kiếm các hạt đó ở khoảng cách bằng hoặc nhỏ hơn. Có lẽ nó sẽ dễ dàng hơn để hạn chế tìm kiếm đối với những người trong một hình vuông trung tâm trong hạt của bạn với chiều cao/widht D (điều này sẽ bao gồm một số hạt quá xa, nhưng sẽ làm cho kiểm tra dễ dàng hơn).

Ngoài ra, trong mã của bạn, bạn đang kiểm tra các va chạm của P1 so với P2 và P2 so với P1 là như nhau, đó là một sự thừa mà bạn có thể tránh dễ dàng.

Các vấn đề liên quan