티스토리 뷰
안녕하세요 Shiny Ocean입니다.
자바를 주제로한 마지막 포스팅입니다. 마지막 포스팅의 주제는 "스레드를 활용한 게임완성"입니다
지금까지 자바언어에 대한 전반적인 내용들을 모두 활용하여서 GUI를 이용한 간단한
피하기 게임을 하나 구현하였습니다.키보드와 모니터를 이용하여 즐길수 있으며
이번 프로젝트를 마지막으로 자바 프로그래밍 카테고리를 종료하겠습니다.
제가 구현할 게임은 톰과제리 게임입니다 이제부터 게임의 구성과 인터페이스, 코딩과정을
상세히 기술해보겠습니다.
1. 제리, 톰, 스파이크 레이블에 이미지아이콘을 추가하여 이미지출력
톰과제리에 나오는 캐릭터(톰, 제리, 스파이크)의 이미지를 첨부하여 컨테이너에 add했습니다.
2. 톰스레드 -> 몬스터 스레드로 변경
제리를 쫒는 몬스터들(톰, 스파이크)의 스레드로 변경했습니다
3. 점수계산
제리가 몬스터를 피하고 있는 동안 +1점
제리가 톰에 닿으면 닿는 시간 동안 -10점
제리가 스파이크(강아지)에 닿으면 점수 -1점으로 초기화(게임 실패)
점수는 0점부터 300점까지, 0점 미만이면 게임실패, 점수계산 스레드 종료
300점 이상이면 게임성공, 점수계산 스레드 종료
그리고 점수가 +되고있을땐 파란색으로 점수레이블글씨 초기화,
-되고 있을땐 빨간색으로 점수레이블글씨 초기화
4. 치즈 레이블을 통한 추가점수 계산
치즈레이블을 추가하여 치즈와 닿아있는동안 점수 +10점
5.게임 종료시 결과를 레이블로 출력
게임에 이겼으면 you win
게임에 졌으면 you lose 텍스트 레이블 출력
1. 제리, 톰, 스파이크 레이블에 이미지아이콘을 추가하여 이미지출력
톰과제리에 나오는 캐릭터(톰, 제리, 스파이크)의 이미지를 첨부하여 컨테이너에 add했습니다.
먼저 게임의 레이블 소개입니다.
가장먼저 제리 입니다.
제리는 키리스너를 통해 키보드의 방향키로 x,y좌표를 바꾸며 게임을 진행합니다.
다음은 톰 입니다.
톰은 제리의 천적으로 몬스터스레드를 통해 제리와 자신의 위치를 비교하며 계속 거리를 좁혀 갑니다.
제리가 톰에 닿을경우 감점 -10점입니다.
다음은 스파이크 입니다.
만화 톰과제리의 동물캐릭터중 가장 강한 캐릭터로 나오는 스파이크는 크기도 제리보다 크고 위력도 강력 합니다.
제리가 스파이크와 닿을경우 점수는 -1점으로 초기화되고 즉시 게임실패입니다.
(점수가 0보다 작을경우 게임실패하도록 스레드를 설정했습니다.)
마지막으로 치즈 입니다.
치즈는 톰과제리에서 제리가 가장좋아하는 음식으로 소개 됩니다.
제리가 치즈와 닿을경우 가산점 +10점입니다.
+점수 레이블
점수 레이블은 프레임의 오른쪽 위 가장자리로 좌표값을 주었고
감점시 빨간색 가산점시 파란색으로 레이블의 색깔이 변합니다.
게임 종료조건 만족시)
게임 실패라면 좌표값을 중앙으로 옮기고, 폰트 사이즈를 크게 한뒤 “you lose”라는 핑크색 레이블을 출력합니다.
게임 성공이면 좌표값을 중앙으로 옮기고, 폰트 사이즈를 크게 한뒤 “you win”라는 하늘색 레이블을 출력합니다.
레이블에 이미지파일을 부착하는 방법은 책p.592의 예제를 통해 알수 있었습니다.
지금까지 레이블에 텍스트로 이미지를 줄때는
JLabel la = new JLabel(“TEXT”);
이러한 꼴로 코딩하여 la라는 레이블에 텍스트를 초기화 했습니다.
하지만 이제부터 사용할 이미지 초기화는
ImageIcon jerryI = new ImageIcon("images/jerry2.jpg");
이런식으로 ImageIcon에 첨부할 파일의 경로를 적어주는형식으로 ImageIcon객체를 먼저 선언하고
JLabel la = new JLabel(jerryI);
선언된 ImageIcon을 레이블에 초기화 하여 부착해줍니다. 나머지 좌표값을 설정하거나, 레이블의 크기를 설정하는등은 원래 하던 방법과 동일합니다. 하지만 setSize를 이미지의 사이즈(픽셀)값 보다 작게 선언해주면 이미지는 본래크기에서 선언된사이즈만큼 잘려서 출력됩니다.
이러한 방법으로 스파이크, 톰,제리를 추가하면
ImageIcon jerryI = new ImageIcon("images/jerry2.jpg");
ImageIcon tomI = new ImageIcon("images/tom.jpg");
ImageIcon spikeI = new ImageIcon("images/spike.jpg");
JLabel jerry = new JLabel(jerryI); //제리
JLabel tom = new JLabel(tomI); //톰
JLabel spike = new JLabel(spikeI); //스파이크(개)
jerry.setLocation(400,400); //제리 시작위치
jerry.setSize(16,26);
c.add(jerry);
tom.setLocation(0,0);
tom.setSize(40,50);
c.add(tom);
spike.setLocation(0,400);
spike.setSize(80,80);
c.add(spike);
이렇게 코딩하였습니다. 치즈레이블은 랜던한위치에서 add되었다가 remove되었다가를 반복해야 하게 때문에 다른 스레드클래스 안에서 부착하였고
점수레이블 또한 감점과 가산점발생시, 게임종료시 위치와 크기, 폰트색을 다르게 출력해야 하기 때문에 다른 스레드클래스 안에서 부착했습니다.
제리레이블의 키리스너클래스는 저번 리포트트에서 자세히 다루었기 때문에 이번 리포트에는 따로 다루지 않겠습니다.
2. 톰스레드 -> 몬스터 스레드로 변경
제리를 쫒는 몬스터들(톰, 스파이크)의 스레드로 변경했습니다
톰의 스레드 클래스에는 저번리포트에서 조금 변형이 되었습니다.
저번리포트에서는 톰의 스레드 클래스를 속도가 빠른 톰,느린톰 두 가지였는데 속도설정방법으로 Thread클래스 두개를 선언하고 sleep()메소드의 시간을 다르게 해주었습니다.
하지만 이번리포트에서는 sleep()안에 들어갈 정수값을 delay라는 int 변수로 선언하고 생성자로 입력받게 하였습니다.
새로운 몬스터인 스파이크 또한 톰 쓰레드와 같이 위치를 비교하며 제리를 쫒는 쓰레드가 필요했기 때문에 톰쓰레드를 몬스터쓰레드라 변경시키고 다음과 같이 코딩하였습니다.
class MonsterThread extends Thread { //제리키 리스너 참고, 저번 리포트 활용, 추가된건 딜레이
JLabel jerry;
JLabel monster;
int delay;
public MonsterThread(JLabel jerry, JLabel monster,int delay) {
this.jerry=jerry;
this.monster=monster;
this.delay = delay; //sleep시간을 생성자를 통해 입력받음
}
public void run() {
while(true) {
if(jerry.getX() < monster.getX()) // 제리가 톰기준 왼쪽위치할떄
monster.setLocation(monster.getX()-5,monster.getY());
else if(jerry.getX() > monster.getX()) // // 제리가 톰기준 오른쪽위치할떄
monster.setLocation(monster.getX()+5,monster.getY());
else monster.setLocation(monster.getX(),monster.getY());
if(jerry.getY() < monster.getY()) // // 제리가 톰기준 위쪽위치할떄
monster.setLocation(monster.getX(),monster.getY()-5);
else if(jerry.getY() > monster.getY()) // 제리가 톰기준 아랴위치할떄
monster.setLocation(monster.getX(),monster.getY()+5);
else monster.setLocation(monster.getX(),monster.getY());
// 스레드를 extends 해서 사용하는 가장큰 기능 sleep
try {
sleep(delay);
}catch(InterruptedException e) {
return;
}
}
}
}
3. 점수계산
제리가 몬스터를 피하고 있는 동안 +1점
제리가 톰에 닿으면 닿는 시간 동안 -10점
제리가 스파이크(강아지)에 닿으면 점수 -1점으로 초기화(게임 실패)
점수는 0점부터 300점까지, 0점 미만이면 게임실패, 점수계산 스레드 종료
300점 이상이면 게임성공, 점수계산 스레드 종료
그리고 점수가 +되고있을땐 파란색으로 점수레이블글씨 초기화,
-되고 있을땐 빨간색으로 점수레이블글씨 초기화
점수계산을 위한 스레드를 하나 선언했습니다. 이 스레드는p.696의 예제로 나오는 타이머스레드와 제리의 키리스너를 응용하여 코딩하였습니다. 각몬스터레이블의 좌표와 제리레이블의 좌표등을 비교하여 감점과 가산점을 계산해야 하기 때문에 이너 클래스로 선언하여 각 객체들의 요소를 바로바로 받아서 사용하였습니다.
점수계산 쓰레드는 300>점수>=0 구간에서 실행되며 점수가 300이상이되면 게임성공을 출력하고 스레드 종료, 0미만이 되면 게임 실패를 출력하고 스레드를 종료 하는 형식입니다.
또, 톰과제리 만화의 최강자 스파이크에게 제리가 잡힌다면 강제로 점수를 -1로 초기화하여 게임을 실패하게 하였습니다.
또 감산시에는 점수레이블의 폰트색을 빨간색으로 가산시에는 폰트색을 파란색으로 바꿔주게 하였고 평상시에는 검정입니다.
감산 = 톰에게 닿았을 때
가산 = 치즈에 닿았을 때, 아무 몬스터에게도 닿지않고 피하고 있을 때
저는 컨테이너와 레이블을 프레임클래스의 내에, 생성자바깥에 선언하여
프레임클래스내의 모든 이너 클래스에서 컨테이너와 생성자를 받아 들일수 있게 했습니다.
이를 종합하여 아래와 같이 점수 계산 쓰레드를 코딩하였습니다.
public class TomAndJerry extends JFrame {
JLabel jerry = new JLabel(jerryI); //제리
JLabel cheeze = new JLabel(cheezeI); //치즈
JLabel tom = new JLabel(tomI); //톰
JLabel spike = new JLabel(spikeI); //스파이크(개)
JLabel scoreLabel = new JLabel(); //점수판
Container c = getContentPane();
int score;
class ScoreThread extends Thread {
@Override
public void run() {
score=0;
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 20));
scoreLabel.setSize(200, 200);
scoreLabel.setLocation(370, -80);
c.add(scoreLabel);
while(true) {
scoreLabel.setText("점수 : "+Integer.toString(score));
score++;
if(jerry.getX()==tom.getX()&&jerry.getY()==tom.getY()){
score-=10; //부딪치면 -10
scoreLabel.setForeground(Color.RED);
}
if(jerry.getX()==spike.getX()&&jerry.getY()==spike.getY()) {
scoreLabel.setForeground(Color.pink);
scoreLabel.setText("you lose");
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 50));
scoreLabel.setLocation(150, 110);
score=-1;
}
if(jerry.getX()<cheeze.getX()+60&&jerry.getX()>cheeze.getX()+15
&& jerry.getY()<cheeze.getY()+22&&jerry.getY()>cheeze.getY()-18 ) {
score+=10; //부딪치면 +10
scoreLabel.setForeground(Color.blue);
}
if(score<0) {
scoreLabel.setForeground(Color.pink);
scoreLabel.setText("you lose");
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 50));
scoreLabel.setLocation(150, 110);
return;
}
if(score>300) {
scoreLabel.setForeground(Color.CYAN);
scoreLabel.setText("you win");
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 50));
scoreLabel.setLocation(150, 110);
return;
}
try {
Thread.sleep(200);
}
catch(InterruptedException e) {
return ;
}
scoreLabel.setForeground(Color.black);
}
}
}
4. 치즈 레이블을 통한 추가점수 계산
치즈레이블을 추가하여 치즈와 닿아있는동안 점수 +10점
점수에 가산을 하는경우는 점수레이블에서 다루었기 때문에 치즈 레이블은 랜던한위치에 add되고 remove되는 쓰레드 클래스만 다루겠습니다.
기본적으로 랜덤한 위치에 계속 레이블이 add되게 하기 위한 코딩은 책의 p.714의 레이블의 로케이션을 랜덤하게 생성하는 예제 코드를 참조했습니다.
하지만 p.714의 예제 13-6의 코드 흐름을 쭉따라가다보면 마우스 액션리스너에서 마우스 클릭시
29번째 줄에contentpane.removeAll(). // 컨텐트팬에 있는 모든 레이블 제거
라고 되어있습니다.
그대로 따라코딩하면 치즈레이블이 랜덤위치에 출력되었다가 사라질 때 열심히 만든 다른 레이블들까지 다 없어질 것 같습니다..
그래서 다른 쓸만한 메소드가 없을까 고민하다가 이클립스에서
contentpane.r.까지 타이핑후 방향키를 내려보니
Remove(component arg0)를 발견했습니다, 컴포넌트를 골라 삭제하는 메소드 같았는데 엔터키를 누르니
직접고를수 있는 항목을 제시해 주기에 치즈 레이블을 생성자로 받은 label 방향키를 내려 선택후 엔터키를 눌러주었습니다.
이렇게 코딩하니 랜덤한 위치에 add된 치즈 레이블만 삭제하고 다시추가 할수 있었습니다, 이제 p.670에서 언급된 repaint 메소드롤 사용하여 컨텐트팬을 다시그려 추가된 레이블을 보이게 만들었습니다.
Ex) contantPane.repaint();
종합하여 치즈레이블을 랜덤한 위치에 출력했다가 사라지게 하는 쓰레드 클래스를 코딩하면 아래와 같습니다.
class RandomLocationThread extends Thread { //p714 랜덤로케이션 생성 ,contentPane.remove 는 removeall에서 자동완성 내리다가 찾음
Container contentPane;
JLabel label;
JLabel jerry;
public RandomLocationThread(Container contentPane,JLabel jerry,JLabel label) {
this.contentPane = contentPane;
this.jerry = jerry;
this.label = label;
}
@Override
public void run() {
while(true) {
label.setSize(80, 30);
label.setLocation((int)(Math.random()*contentPane.getWidth()),
(int)(Math.random()*contentPane.getHeight()));
contentPane.add(label); // 레이블을 컨텐트팬에 추가
contentPane.repaint(); // 컨텐트팬을 다시 그려 추가된 레이블이 보이게 함
try {
Thread.sleep(5000); // 5초 동안 잠을 잔다.
contentPane.remove(label);
}
catch(InterruptedException e) { return; }
}
}
}
5.게임 종료시 결과를 레이블로 출력
게임에 이겼으면 you win
게임에 졌으면 you lose 텍스트 레이블 출력
점수계산 스레드 안에 조건문을 추가해 게임 실패와 성공여부를 출력했습니다.
실패 또는 성공시에는 run() 메소드 안에 return을 통한 쓰레드 종료를 시켰습니다.
if(score<0) { //0점 아래면 루즈 라벨 출력후 종료
scoreLabel.setForeground(Color.pink);
scoreLabel.setText("you lose");
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 50));
scoreLabel.setLocation(150, 110);
return;
}
if(score>300) { //300점 이상이면 윈 라벨 출력후 종료
scoreLabel.setForeground(Color.CYAN);
scoreLabel.setText("you win");
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 50));
scoreLabel.setLocation(150, 110);
return;
}
+@
아바타는 상하좌우 키를 이용하여 패널상에서 움직이면서 도망간다 (한번 키 입력할 때마다 10픽셀씩 이동)
제 코드의 경우 아바타는 제리입니다. 제리의 움직임을 키보드의 방향키 입력으로 받기 위해 필요한 키리스너클래스를 이너 클래스로 선언하였습니다.
톰의 쓰레드클래스의 경우는 나중에 톰을 여러마리로 늘리면 각각의 여러 쓰레드가 필요하기 때문에 클래스를 많이 추가해주어야 할 것 같았습니다. 프레임클래스 내에 이너클래스로 선언하면 복잡하게 보일 것 같아서, 프레임클래스 밖에서 독립적으로 선언하고 생성자를 통해 톰과 제리 레이블을 초기화했습니다.
본론으로 돌아와 제리의 키리스너클래스는 키이벤트들을 받아들이는 keypressed를 오버라이딩한 클래스 하나만 있으면 되기 때문에 이너클래스로 선언했습니다.
p.565의 코드를 참고하여 프레임의 생성자내의 컨테이너에 키리스너를 추가했습니다.
c.addKeyListener(new JerryKeyListener());
그리고 키리스너 클래스를 다음과 같이 구현했습니다,
class JerryKeyListener extends KeyAdapter { //p565 키 이벤트
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode(); // 입력된 키의 키코드를 알아낸다.
if(e.getKeyChar() == 'q')
System.exit(0); //p559
switch(keyCode) { //키보드의 방향키에따른 키이밴트
case KeyEvent.VK_UP:
jerry.setLocation(jerry.getX(), jerry.getY()-10); break;
case KeyEvent.VK_DOWN:
jerry.setLocation(jerry.getX(), jerry.getY()+10); break;
case KeyEvent.VK_LEFT:
jerry.setLocation(jerry.getX()-10, jerry.getY()); break;
case KeyEvent.VK_RIGHT:
jerry.setLocation(jerry.getX()+10, jerry.getY()); break;
}
}
}
셋레이아웃을 null로 해주었기 때문에 레이블의 위치좌표를 JLabel의 setLocation() ,getX(), getY()메소드를 통해 초기화 해줄수 있습니다.
이제 제 코드의 “jerry”레이블은 키보드가 눌릴때마다 발생하는 이벤트를 통해 위치 변경이 가능해졌습니다.
오직 ‘q’키를 입력하여 이 게임은 종료된다
p599에서 설명된 키이벤트의 getkeychar메소드를 사용한다.
키 리스너 이벤트이기 때문에 제리 키 리스너 클래스내에 포합시켜 코딩했습니다.
class JerryKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode(); // 입력된 키의 키코드를 알아낸다.
if(e.getKeyChar() == 'q')
System.exit(0); }
전체 코드)
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class TomAndJerry extends JFrame {
//p592 레이블에 이미지 첨부
ImageIcon jerryI = new ImageIcon("images/jerry2.jpg");
ImageIcon tomI = new ImageIcon("images/tom.jpg");
ImageIcon spikeI = new ImageIcon("images/spike.jpg");
ImageIcon cheezeI = new ImageIcon("images/cheeze.jpg");
JLabel jerry = new JLabel(jerryI); //제리
JLabel cheeze = new JLabel(cheezeI); //치즈
JLabel tom = new JLabel(tomI); //톰
JLabel spike = new JLabel(spikeI); //스파이크(개)
JLabel scoreLabel = new JLabel(); //점수판
Container c = getContentPane(); //공용 content pain, 치즈 위치를 계속 리페인트 리무브하기위해 여기 선언
int score; //점수
public TomAndJerry() { //p565
setTitle("Tom&Jerry");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
c.setLayout(null);
jerry.setLocation(400,400); //제리 시작위치
jerry.setSize(16,26);
c.add(jerry);
tom.setLocation(0,0);
tom.setSize(40,50);
c.add(tom);
spike.setLocation(0,400);
spike.setSize(80,80);
c.add(spike);
c.addKeyListener(new JerryKeyListener());
c.setFocusable(true);
c.requestFocus();
setSize(500,500);
setVisible(true);
MonsterThread tomThread = new MonsterThread(jerry,tom, 40);
tomThread.start();
MonsterThread spikeThread = new MonsterThread(jerry,spike, 90);
spikeThread.start();
RandomLocationThread cheezeLocation = new RandomLocationThread(c,jerry,cheeze);
cheezeLocation.start();
ScoreThread score = new ScoreThread();
score.start();
}
class JerryKeyListener extends KeyAdapter { //p565
int jerrySpeed=15;
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(e.getKeyChar() == 'q')
System.exit(0); //p559
switch(keyCode) {
case KeyEvent.VK_UP:
jerry.setLocation(jerry.getX(), jerry.getY()-jerrySpeed); break;
case KeyEvent.VK_DOWN:
jerry.setLocation(jerry.getX(), jerry.getY()+jerrySpeed); break;
case KeyEvent.VK_LEFT:
jerry.setLocation(jerry.getX()-jerrySpeed, jerry.getY()); break;
case KeyEvent.VK_RIGHT:
jerry.setLocation(jerry.getX()+jerrySpeed, jerry.getY()); break;
}
}
}
class ScoreThread extends Thread {
@Override
public void run() {
score=0;
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 20));
scoreLabel.setSize(200, 200);
scoreLabel.setLocation(370, -80);
c.add(scoreLabel);
while(true) {
scoreLabel.setText("점수 : "+Integer.toString(score));
score++;
if(jerry.getX()==tom.getX()&&jerry.getY()==tom.getY()){
score-=10; //부딪치면 -10
scoreLabel.setForeground(Color.RED);
}
if(jerry.getX()==spike.getX()&&jerry.getY()==spike.getY()) { //닿으면 스레드 종료
scoreLabel.setForeground(Color.pink);
scoreLabel.setText("you lose");
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 50));
scoreLabel.setLocation(150, 110);
return;
}
if(jerry.getX()<cheeze.getX()+60&&jerry.getX()>cheeze.getX()+15
&& jerry.getY()<cheeze.getY()+22&&jerry.getY()>cheeze.getY()-18 ) {
score+=10; //부딪치면 -10
scoreLabel.setForeground(Color.blue);
}
if(score<0) { //0점 아래면 루즈 라벨 출력후 종료
scoreLabel.setForeground(Color.pink);
scoreLabel.setText("you lose");
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 50));
scoreLabel.setLocation(150, 110);
return;
}
if(score>300) { //300점 이상이면 윈 라벨 출력후 종료
scoreLabel.setForeground(Color.CYAN);
scoreLabel.setText("you win");
scoreLabel.setFont(new Font("Gothic", Font.ITALIC, 50));
scoreLabel.setLocation(150, 110);
return;
}
try {
Thread.sleep(200);
}
catch(InterruptedException e) {
return ;
}
scoreLabel.setForeground(Color.black);
}
}
}
public static void main(String [] args) {
new TomAndJerry();
}
}
class MonsterThread extends Thread { //제리키 리스너 참고, 저번 리포트 활용, 추가된건 딜레이
JLabel jerry;
JLabel monster;
int delay;
public MonsterThread(JLabel jerry, JLabel monster,int delay) {
this.jerry=jerry;
this.monster=monster;
this.delay = delay;
}
public void run() {
while(true) {
if(jerry.getX() < monster.getX()) // 제리가 톰기준 왼쪽위치할떄
monster.setLocation(monster.getX()-5,monster.getY());
else if(jerry.getX() > monster.getX()) // // 제리가 톰기준 오른쪽위치할떄
monster.setLocation(monster.getX()+5,monster.getY());
else monster.setLocation(monster.getX(),monster.getY());
if(jerry.getY() < monster.getY()) // // 제리가 톰기준 위쪽위치할떄
monster.setLocation(monster.getX(),monster.getY()-5);
else if(jerry.getY() > monster.getY()) // 제리가 톰기준 아랴위치할떄
monster.setLocation(monster.getX(),monster.getY()+5);
else monster.setLocation(monster.getX(),monster.getY());
// 스레드를 extends 해서 사용하는 가장큰 기능 sleep
try {
sleep(delay);
}catch(InterruptedException e) {
return;
}
}
}
}
class RandomLocationThread extends Thread { //p714 랜덤로케이션 생성 ,contentPane.remove 는 removeall에서 자동완성 내리다가 찾음
Container contentPane;
JLabel label;
JLabel jerry;
public RandomLocationThread(Container contentPane,JLabel jerry,JLabel label) {
this.contentPane = contentPane;
this.jerry = jerry;
this.label = label;
}
@Override
public void run() {
while(true) {
label.setSize(80, 30);
label.setLocation((int)(Math.random()*contentPane.getWidth()),
(int)(Math.random()*contentPane.getHeight()));
contentPane.add(label); // 레이블을 컨텐트팬에 추가
contentPane.repaint(); // 컨텐트팬을 다시 그려 추가된 레이블이 보이게 함
try {
Thread.sleep(5000); // 0.3초 동안 잠을 잔다.
contentPane.remove(label);
}
catch(InterruptedException e) { return; }
}
}
}
결과 화면)
'Language > Java' 카테고리의 다른 글
Java - DB 기능 구현 예제 (1) | 2021.09.08 |
---|---|
Java - Swing, Jslider 스윙과 슬라이더 (0) | 2021.01.28 |
Java - Class의 상속과 메소드 응용 (0) | 2021.01.28 |
Java - 간단한 끝말잇기 텍스트게임 구현 (1) | 2021.01.28 |
Java - Abstract Class, 추상클래스 (0) | 2021.01.28 |