자바 쓰레드 리스트 관련 질문 부탁드립니다.

조회수 952회

지금 awt를 이용해서 공 5개를 튕긴후에 공끼리 서로 충돌할 때 마다, 두개로 쪼개져서 튕기고, 그러다가 크기가 1픽셀 이하 일때 사라지는 프로그램 코딩중인데... 이 시간까지 해도 해결이 되지가 않네요 ㅠㅠ import java.awt.*;

import java.awt.event.*;

import java.math.*;

import java.util.ArrayList;

    public class BounceThread extends Frame implements ActionListener  {
    private Canvas canvas;
    ArrayList<Ball> threadList = new ArrayList<Ball>();
public BounceThread(String title) {
super(title);
canvas = new Canvas();
add("Center", canvas);
Panel p = new Panel();
Button s = new Button("Start");
Button c = new Button("Close");
p.add(s); p.add(c);
s.addActionListener(this);
c.addActionListener(this);
add("South", p); }

public void actionPerformed(ActionEvent evt) {
    if (evt.getActionCommand() == "Start") {            

            for(int i=0;i<5;i++) {
                threadList.add(new Ball(canvas,200,150,20,i*(Math.PI/5)));
                //threadList.add(k);
                threadList.get(i).start();
            }

    }
    else if (evt.getActionCommand() == "Close")
    System.exit(0); }



public static void main(String[] args) {
    // TODO Auto-generated method stub
    Frame f = new BounceThread("Bounce Thread");
    f.setSize(400, 300);
    WindowDestroyer listener = new WindowDestroyer();
    f.addWindowListener(listener);
    f.setVisible(true); 
}

class Ball extends Thread{
    private Canvas box;
    int check;
    boolean runable=true;
    private int XSIZE;
    private int YSIZE;
    private double dx = 2;
    private double dy;
    double radian;
    private int x ; 
    private int y ;
    //Graphics g;
    public Ball(Canvas c,int x, int y, int X, double n) {
    box = canvas; 
    this.x= x;
    this.y= y;
    this.XSIZE= X;
    this.YSIZE= X;
    //this.check=m;
    this.radian=n;
    this.dy = dx*Math.tan(n);
    if(n>=Math.PI/2 && n<3*Math.PI/2){
           this.dx = -this.dx;
        }
    }

    public void draw() {
        Graphics g = box.getGraphics();
        g.fillOval(x, y, XSIZE, YSIZE);
        g.dispose(); 
    }
    public void move() {    
    Graphics g = box.getGraphics();
    g = box.getGraphics();  
    g.setColor(Color.white);
    g.fillOval(x, y, XSIZE, YSIZE);
    x += dx; y += dy;
    Dimension d = box.getSize();
    if (x < 0) { x = 0; dx = -dx; }     
    if (x + XSIZE >= d.width) { x = d.width - XSIZE; dx = -dx;}
    if (y < 0) { y = 0; dy = -dy; }
    if (y + YSIZE >= d.height) {y = d.height - YSIZE; dy = -dy; }

    for(int i=0;i<threadList.size();i++) {
        Ball x=threadList.get(i);
        if(this.collide(x))
        {           
            if(i!=threadList.indexOf(this)) {
                 System.out.println(threadList.indexOf(this)+" "+"size="+threadList.size()+" "+"i="+i);
                this.split(this,x);
            }
            }

    }   
    g.setColor(Color.black);
    g.fillOval(x, y, XSIZE, XSIZE);
    g.dispose(); }

    public boolean collide(Ball ball){
          int distanceX = this.x - ball.x;
          int distanceY = this.y - ball.y;
          double distance = Math.sqrt((distanceX * distanceX) + (distanceY * distanceY));
          if(distance <= (this.XSIZE + ball.XSIZE)/2){
               double distanceXPrime = (this.x + this.dx) - (ball.x + ball.dx);
               double distanceYPrime = (this.y + this.dy) - (ball.y + ball.dy);
               double distancePrime = Math.sqrt(distanceXPrime * distanceXPrime + distanceYPrime * distanceYPrime);
               if(distance > distancePrime){
                return true;
               }
              }
              return false;
             }

    //@SuppressWarnings("deprecation")
    public void splitTwo(Ball ball, double rad){
          double subtractedRadOfBall = rad - Math.PI/4;
          double addedRadOfBall = rad + Math.PI/4;
          //반지름이 1보다 크면 기존 원은 사라지고 작은원 둘로 나뉜다.
          if(ball.XSIZE/2>1){
           //ball.runable=false;
              Ball new1 = new Ball(box,ball.x,ball.y,ball.XSIZE/2, subtractedRadOfBall);
           //balist[check].start();
              Ball new2 = new Ball(box,ball.x,ball.y,ball.XSIZE/2, addedRadOfBall);
           //balist[l].start(); 
              ball.interrupt();
              threadList.remove(threadList.get(threadList.indexOf(this)));
              //System.out.println(threadList.indexOf(ball)+"what "+"size="+threadList.size());
              threadList.add(new1);
              threadList.add(new2);
              new1.start();
              new2.start();
          }
          //반지름이 1보다 작으면 사라진다.
          else{
           ball.interrupt();
           threadList.remove(threadList.get(threadList.indexOf(this)));
           //ball.runable = false;
          }

    }



    public void split(Ball ballOne, Ball ballTwo){
          //ballOne 과 ballTwo의 충돌 이후 진행 방향을 벡터로 계산하였다.
          double newRadOfBallOne = (ballOne.XSIZE/2*Math.sin(ballOne.radian)-ballTwo.y+ballOne.y)/(ballOne.XSIZE/2*Math.cos(ballOne.radian)-ballTwo.x+ballOne.x);
          double newRadOfBallTwo = (ballTwo.XSIZE/2*Math.sin(ballTwo.radian)-ballOne.y+ballTwo.y)/(ballTwo.XSIZE/2*Math.cos(ballTwo.radian)-ballOne.x+ballTwo.x);

          splitTwo(ballOne, newRadOfBallOne);
          //System.out.println(threadList.indexOf(ballOne)+"what "+"size="+threadList.size());
          splitTwo(ballTwo, newRadOfBallTwo);  
         }

    public void run() {
    draw();
    while(!Thread.currentThread().isInterrupted()) {
    this.move();
    try { Thread.sleep(20); }
    catch(InterruptedException e) {}    
    }
    }
    }
}
    public class WindowDestroyer extends WindowAdapter {

public void windowClosing(WindowEvent e) {
    System.exit(0);
}

}

이런 코드인데 Exception in thread "Thread-35" java.lang.ArrayIndexOutOfBoundsException: -1 at java.util.ArrayList.elementData(Unknown Source) at java.util.ArrayList.get(Unknown Source) at BounceThread$Ball.splitTwo(BounceThread.java:131) at BounceThread$Ball.split(BounceThread.java:156) at BounceThread$Ball.move(BounceThread.java:95) at BounceThread$Ball.run(BounceThread.java:162)

이런식으로 자꾸 인덱스 범위를 넘었다는 에러가 뜨는데 도대체 이유를 모르겠습니다.. 고수님들 부탁드립니다 ㅠㅠ

  • (•́ ✖ •̀)
    알 수 없는 사용자
  • JDK는 버전 몇으로 하셨나요? 돌려보려고 했더니 WindowDestroyer를 못찾겠네요. 편집요청빌런 2018.11.21 13:44
  • 아 WindowDestroyer는 제가 따로 패키지 안에 구현해 놓았습니다! jdk 1.8.0_191 이라고 되어있네요!!! 알 수 없는 사용자 2018.11.21 13:48
  • 질문 다시 수정하였씁니다! 알 수 없는 사용자 2018.11.21 14:21

1 답변

  • 소스를 정확하게 파악하진 못했지만 일단 splitTwo()함수 안에서

    if (){
      threadList.remove(threadList.get(threadList.indexOf(this)));
    } else {
      threadList.remove(threadList.get(threadList.indexOf(this)));
    }
    

    이렇게 remove 하려는 코드가 두개 있는데요. indexOf함수는 찾으려는 요소가 없으면 -1을 반환합니다. -1이 리턴되었는데 remove하려고 하니 ArrayIndexOutOfBoundsException이 발생하는것입니다. 빠르게 에러를 막으려면 indexOf리턴값이 -1이거나 threadList.size()보다 더 크면 remove하지 않도록 조건을 넣으면 에러는 발생하지 않을것입니다.

    자바코드 참고

        /**
         * Returns the index of the first occurrence of the specified element
         * in this list, or -1 if this list does not contain the element.
         * More formally, returns the lowest index <tt>i</tt> such that
         * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
         * or -1 if there is no such index.
         */
        public int indexOf(Object o) {
            if (o == null) {
                for (int i = 0; i < size; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = 0; i < size; i++)
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }
    
    
    • (•́ ✖ •̀)
      알 수 없는 사용자
    • 감사합니다! 결국 코드를 전체적으로 바꾼후에야 돌아갔는데 한번 이 방법으로도 돌려봐야겠어요! 알 수 없는 사용자 2018.11.24 16:19

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)