2012-11-22 3 views
6

입자 시스템 애플릿을 작성했습니다. 현재 저는 각 파티클을 별도로 만들고 있습니다. 내가 20,000 입자 (나는 괜찮은 노트북을 가지고 있지만)와 함께 ~ 40FPS를 얻을 수있는, 성능이 괜찮습니다입니다입자를 효율적으로 그리기

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


      } 
    } 

} 

(여기에 코드입니다). 내가 (아래 참조) 충돌 감지 기능을 추가 한 후, 나는이 화면에 입자 그리기 더 나은 방법을 꽤 검색 한

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


    } 

그 수는 2000 미만으로 하락하지만 예 중 저를 혼동 적용 할 수 없었습니다.

계산이 너무 많습니다 (너무 많음). 그러나 나는 그것을하는 다른 방법을 생각할 수 없었다, 제안은 환영 받는다.

+0

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

+0

어느 것이 가장 도움이되었는지 결정한 후에는 대답을 받아 들여야합니다. – PearsonArtPhoto

답변

5

우선 충돌 감지와 같은 기능을 추가하면 항상 많은 메모리가 필요합니다. 그러나

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

이의 척하자 귀하의 충돌 감지 알고리즘을 살펴 보자 당신은 순서 1,1 1, 2 2,1 2,2에서 확인에만 2 입자 1과 2가 있었다

사실이 경우에는 1 대 2 만 확인하면됩니다. 1을 치면 2, 2도 1을 치게됩니다. 따라서 이전에 테스트 한 for 루프 건너 뛰기와 동일한 번호를 변경하십시오.

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++) { 

내가주의 또 다른 것은 당신이 sqrt 작업을 수행하지만 정적 숫자 모양을 비교하는 것입니다. 이를 제거하고 제곱 된 수와 비교하면 커다란 개선점이 생깁니다. 특히 많은 것을 할 때 더욱 그렇습니다.

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

이와 같은 개선 사항을 계속 찾으십시오. 그런 다음 다른 클래스, 스레딩 등을 사용하여 시스템을 개선 할 수있는 다른 옵션을 신중하게 살펴볼 수 있습니다. 하지만 먼저 코드를 최적화 할 수 있어야합니다. 다음은 제가 대략 시도 할 다른 것들의 목록입니다.

  1. 내가 들어온 후에 다른 것을 계산하기도 전에 입자 i가 살아 있는지 확인하십시오.
  2. 페어를 빠르게 지나치게 가까이에서 확인하는 것만으로도 세부적으로 확인하십시오. 간단한 방법은 sqrt 연산을 수행하기 전에 x 및 y 차원 내에 있는지 먼저 확인하는 것입니다. 복잡한 테스트를하기 전에 항상 가장 저렴한 테스트를 먼저 수행하십시오.
  3. 코드를보고 실제로 계산 된 값을 모두 사용하는지 또는 어떻게 든 작업 수를 줄일 수 있는지 확인하십시오.
  4. 아마도 광범위한 뇌졸중으로 정기적으로 이미지를 클러스터링 한 다음 일정 기간 동안 초기 클러스터를 통과 한 객체 만 구체화 한 다음 광범위한 클러스터 알고리즘을 수행 할 수 있습니다.
  5. 충돌 감지를 스레드 할 수 있습니다. 그러나이 작업을 수행하려는 경우 무언가 충돌했는지 확인하기 위해 검사를 스레드해야하며 모든 스레드가 완료된 후에는보기의 개체를 업데이트해야합니다.
  6. 일을 더 빠르게 할 수있는 대체 아키텍처를 살펴보십시오.
+0

고마워, 내 생각 엔 (중첩 된)하지만 내 머리에서 나오지 않을거야. (+1했다.) – user1159424

+0

문제 없습니다. 이와 같은 것들을 최적화하는 것이 아마도 프로그래밍에서 가장 좋아하는 부분 일 것입니다 :-) – PearsonArtPhoto

+0

또한 입자가 움직 였는지 확인하는 것은 어떻습니까? 마지막 프레임 이후로 이동 한 입자 만 그립니다. 충돌시에도 마찬가지입니다. 움직이지 않은 입자 2 개는 서로 충돌하지 않습니다. –

4

페인팅은 여러 가지 이유로 트리거 될 수 있습니다. 운영체제에서 창을 업데이트하고 재 페인트 관리자가 다시 그리기를 원할 수 있으므로 프로그래머가 다시 그리기를 원할 수 있습니다.

paint 프로세스 내의 입자를 업데이트하는 것은 좋지 않습니다. 원하는 것은 별도의 버퍼에있는 별도의 스레드에서 입자를 업데이트하는 것입니다. 준비가되면, 버퍼의 페인트를 담당하는 컴퍼넌트에 페인트를 실시해, 새로운 버퍼의 카피를 페인트에 다시 건네 주도록 (화면에 갱신 된 버퍼에 페인트하고 싶지 않으면, 결국 더러운 페인트로 끝날 것입니다.)

코드에서 알기는 어렵지만 java.awt.Applet을 사용하고있는 것으로 보입니다. 개인적으로는 으로 업그레이드 할 예정입니다.

그림을 java.swing.JPanel으로 옮길 것입니다. 스윙 구성 요소는 이중 버퍼링 (다른 버퍼링 전략은 물론)을 제공합니다. 이 패널에있는 유일한 작업은 입자 엔진에 새로운 프레임이있을 때 화면에 버퍼를 페인트하는 것입니다.

입자 엔진은 모든 입자를 업데이트하고이 결과를지지 버퍼 (BufferedImage)로 페인팅해야합니다. 그러면이 입자가 패널에 전달되어 패널이 사본을 만들고 업데이트를 예약합니다.

스윙은 안전하지 않습니다. 즉, Event Dispatching Thread 이외의 스레드에서 UI를 변경하면 안됩니다. 이를 위해 Concurrency in Swing을 통해 읽은 화면 버퍼를 클라이언트에 다시 동기화하는 솔루션을 원할 수도 있습니다.

+0

+1 좋은 지점 : P – MadProgrammer

+0

매우 유익한, 타이 – user1159424

0

모든 입자와 충돌하는 것을 확인하고 있습니다.이 입자는 n^2 정도의 순서로 매우 자세합니다 (2,000 입자는 각 프레임에 대해 4,000,000 개의 조합을 의미 함).

문제는 자바가 아니라 알고리즘입니다. 더 나은 선택이 있어야하지만, 당신과 비교를 줄여 줄 수 있습니다; 최대 속도 S가 있고 세계 시간이 T만큼 증가하면 T * S로 고려중인 입자와 충돌 할 수있는 입자의 최대 거리 D를 얻습니다. 거리가 같거나 작은 입자로 검색을 줄이십시오. 어쩌면 높이/넓이가 D 인 입자에 중심을 둔 정사각형으로 검색을 제한하는 것이 더 쉬울 것입니다 (여기에는 너무 먼 입자가 포함되지만 검사가 더 쉬워집니다).

또한 코드에서 P1 대 P2와 P2 대 P1의 충돌, 즉 쉽게 피할 수있는 중복성을 확인하고 있습니다.