Thread를 이용한 경주게임
- 예제를 이용한 java programming -
Thread를 이용한 애니매이션 경주 게임
이번 포스트에서는 Java의 Thread를 이용하여 애니매이션 효과를 주는 동시에 게임형식으로 프로그램을 코딩할 것이다.
먼저 해당하는 객체를 나누는 작업을 UML로 작성한 후 프로그램 코딩을 들어가면 한결 수월해 질 것이다.
예제를 이용한 화면은 아래와 같다. 프레임을 활용하며 버튼을 이용해 게임을 만들 것이다.
1) 경주중인 모습
2) 도착후 그 결과를 보여준다.
먼저 MyFrame 클래스를 MyHorse 클래스로 나누어 코딩을 할 것이다.
MyFrame 클래스는 프레임 객체를 생성하는 클래스 이므로 프레임에 해당하는 너비, 높이와, 필요한 버튼과 결과창을 보여줄 텍스트뷰.
그리고 쓰레드 클래스의 인터페이스인 Runnable을 이용하여 run 함수에 이미지가 반복적으로 그려지게 할 것이다.
>> 프레임 생성자함수에는 크기에 대한 값과 필요한 함수들을 선언해 줄 것이다.
public MyFrame() {
setVisible(true);
setSize(FRAME_WIDTH, FRAME_HEIGHT);
makeHorse();
makeUi();
Thread t = new Thread(this);
t.start();
}
>> synchronized를 이용하여 서로 다른 쓰레드에서 함수를 호출할 때 두 메소드가 동시에 일어나지 않도록 하는 함수이다.
그럼 배열에 MyHorse 클래스에서 생성한 객체를 담아 주도록 한다. (버튼 생성에 대한 내용은 생략하도록 하겠다.)
private synchronized void makeHorse() {
for (int i = 0; i < HORSE_SIZE; i++) {
arr[i] = new MyHorse();
}
}
>> 해당 버튼이 클릭되었을 때 Action이 수행 될 수 있도록 내부클래스를 선언하여 알맞은 코딩을 다루게 한다.
class MyHanler implements ActionListener {
>> 게임시작 버튼 클릭시에 배열이 담긴 쓰레드 클래스를 start()함수로 호출하고 rrepaint되면서 계속 새로운 그림이 그려질 수 있도록 한다.
종료 버튼 클릭시에는 프레임 창이 종료된다.
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == btn_start) {
for (int i = 0; i < HORSE_SIZE; i++) {
(new Thread(arr[i])).start();
repaint();
}
} else if (e.getSource() == btn_close) {
dispose();
System.exit(0);
}
}
}
>> 그림이 담긴 배열을 while 반복문을 통해 계속 돌아가게 하는 코딩이다. 경기가 종료될때 등수를 찍어내도록 한다.
@Override
public void run() {
boolean temp = false;
int count = 0;
while (!temp) {
for (int i = 0; i < arr.length; i++) {
if (arr[i].state) {
txta.append(arr[i].getMy_score() + "등 : " + arr[i].getNum()
+ "번 말!! \n");
arr[i].state = false;
>> 해당 포스트에는 그림을 4개만 사용하였기 때문에 count가 5가 되면 다시 처음부터 그림을 돌릴 수 있도록 하는 부분이다.
if (count == 5) {
temp = true;
} else {
count++;
}// end if
}// end if
}// end for
}// end while
}// end run
};
// ---------------------------------------- MyHorse 클래스
public class MyHorse extends Canvas implements Runnable {
public static final int HORSE_SIZE = 50;
private static int score;
private int my_score = 0;
private String[] ImgAddr = new String[4];
private Image img;
private int x = 10;
private int speed = 1;
public static int num_plus = 1;
private int num;
private int ImgCount = 0;
// 추가 코드
public boolean state = false;
public MyHorse() {
num = num_plus++;
imgAddr();
}
public void imgAddr() {
ImgAddr[0] = "tt1.png";
ImgAddr[1] = "tt2.png";
ImgAddr[2] = "tt3.png";
ImgAddr[3] = "tt4.png";
}
@Override
public void paint(Graphics g) { // 페인트가 불릴때 캔버스 싸이즈가 결정된다.
setSize(this.getWidth(), 100);
setBackground(Color.black);
g.setColor(Color.orange);
g.drawString(num + "번", x + 15,
(getHeight() / 2 - (HORSE_SIZE) / 2) - 5);
g.drawImage(img, x, getHeight() / 2 - (HORSE_SIZE) / 2, HORSE_SIZE,
HORSE_SIZE, this);
// g.drawImage(t1, x, y, observer);
if (ImgCount == 4) {
ImgCount = 0;
} else {
img = Toolkit.getDefaultToolkit().getImage(ImgAddr[ImgCount]);
ImgCount++;
}
}
public void animation() {
}
@Override
public void run() {
while (true) {
if (x < MyFrame.FRAME_WIDTH - 70) {
speed = (int) (Math.random() * 10) + 9;
x += speed;
repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
x = MyFrame.FRAME_WIDTH - 60;
my_score = ++score;
state = true;
System.out.println("번 말" + ", " + "등수 :" + my_score);
repaint();
break;
}
}
}
public void getImage() {
}
public int getMy_score() {
return my_score;
}// end getMy_score
public int getNum() {
return num;
}// end getNum
};