노션에 나와있는 망나니 잡기 코드를 실행하면 수행되는 동작은 크게 세 가지이다.
1. 망나니를 두 번 클릭하면 모든 스레드가 종료된다.
2. 병아리, 거북이는 오른쪽으로 이동하고, 토끼는 아래로 결승선에 닿을 때까지 이동한다.
3. 병아리, 거북이, 토끼 버튼을 클릭할수록 속도?가 점점 줄어든다.
이를 이용해서 망나니 잡기 실습을 따라하되, 조금 변형을 주었다.
기본 규칙은 동일하지만 아래로 가는 토끼를 똑같이 오른쪽으로 이동하도록 수정하고, 결승선 뿐만 아니라 출발선도 만들었다.
그리고 속도가 마이너스가 되면 이동 방향의 반대로 이동하면서 출발선에 닿으면 멈추도록 만드는 것이다!
너무 식상한가...
그래서 헷갈리는 점을 좀 찾아봤는데... 병아리, 토끼, 거북이를 클릭할 때 나오는 '속도'는 진짜 속도가 아니라 delay 값이라 0이 되면 결승선으로 바로 순간이동해버린다. 왜냐면 딜레이 값이 0이 되면 이동하면서 '쉬지' 않기 때문에 바로 파바밧 이동해서 결승선에 가게 되는 것이다!
그래서 속도 표기가 진짜 속도가 되도록 수정하고 이게 마이너스 값이 되면 반대로 이동하도록 변경을 주는 것을 목표로 잡았다.
1. MyView.java
package t20251102;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.event.*;
public class MyView extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTextField moveSpeed;
private JButton startButton;
private Player p1= new Player("귀여운 병아리", 100,20,400);
private Player p2= new Player("겁나 빠른 거북이", 100,20,100);
private Player p3= new Player("정신없는 망나니!", 100,20,500);
private Player p4= new Player("잠꾸러기 토끼", 100,20,500);
PlayerButton bt3=new PlayerButton(p3);
PlayerButton bt1=new PlayerButton(p1);
PlayerButton bt4=new PlayerButton(p4);
PlayerButton bt2=new PlayerButton(p2);
private final JPanel 결승선_1 = new JPanel();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MyView frame = new MyView();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyView() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 825, 619);
contentPane = new JPanel();
contentPane.setBorder(new LineBorder(Color.BLACK, 4));
setContentPane(contentPane);
contentPane.setLayout(null);
bt3.setBackground(new Color(255, 0, 0));
bt3.setBounds(26, 98, 180, 52);
bt3.setMovementType(MovementType.RANDOM);
contentPane.add(bt3);
bt1.setForeground(new Color(0, 0, 0));
bt1.setBackground(new Color(255, 255, 128));
bt1.setBounds(26, 220, 180, 52);
contentPane.add(bt1);
bt4.setBackground(new Color(255, 128, 192));
bt4.setBounds(26, 333, 180, 52);
contentPane.add(bt4);
bt2.setBackground(new Color(0, 255, 64));
bt2.setBounds(26, 452, 180, 52);
contentPane.add(bt2);
JPanel 결승선 = new JPanel();
결승선.setBackground(new Color(255, 0, 0));
결승선.setForeground(new Color(0, 0, 0));
결승선.setBounds(650, 54, 10, 518);
contentPane.add(결승선);
startButton = new JButton("이 버튼을 눌러서 시작!!");
startButton.addActionListener(this);
startButton.setBounds(135, 12, 378, 41);
contentPane.add(startButton);
moveSpeed = new JTextField();
moveSpeed.setText("500");
moveSpeed.setBounds(530, 32, 96, 21);
contentPane.add(moveSpeed);
moveSpeed.setColumns(10);
결승선_1.setForeground(Color.BLACK);
결승선_1.setBackground(Color.RED);
결승선_1.setBounds(12, 54, 10, 518);
contentPane.add(결승선_1);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == startButton) {
System.out.println("Start 버튼 눌림");
try {
int delay = Integer.parseInt(moveSpeed.getText());
p3.setDelay(delay);
} catch (NumberFormatException ex) {
System.err.println("유효하지 않은 숫자입니다. 기본값 500으로 설정합니다.");
p3.setDelay(500);
}
bt1.start();
bt2.start();
bt3.start();
bt4.start();
startButton.setEnabled(false);
this.requestFocus();
}
}
}

2. Player.java
package t20251102;
import java.util.ArrayList;
import java.util.Random;
public class Player {
private String name;
private int hp;
private int power;
private int delay;
public Player() {}
public Player(String name, int hp, int power, int delay) {
this();
this.name = name;
this.hp = hp;
this.power = power;
this.delay = delay;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHp() {
return hp;
}
public void setHp(int hp) {
this.hp = hp;
}
public int getPower() {
return power;
}
public void setPower(int power) {
this.power = power;
}
public int getDelay() {
return delay;
}
public void setDelay(int delay) {
this.delay = delay;
}
}
3. PlayerButton.java
package t20251102;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
enum MovementType {
RIGHT, LEFT, DOWN, RANDOM
}
public class PlayerButton extends JButton implements Runnable, ActionListener{
Player p=null;
Thread th;
boolean running = true;
private static final int BASE_SPEED_REFERENCE = 500;
private MovementType movementType = MovementType.RIGHT;
public PlayerButton(){
this.setSize(200, 50);
this.setBackground(Color.lightGray);
this.addActionListener(this);
}
public PlayerButton(Player p){
this();
this.p = p;
this.setText(p.getName());
this.setOpaque(true);
}
public void start(){
running = true;
th = new Thread(this);
th.start();
}
public void changeColor(){
Random r= new Random();
int red = r.nextInt(50) + 200;
int green = r.nextInt(100) + 100;
int blue = r.nextInt(50) + 200;
this.setBackground(new Color(red, green, blue));
}
@Override
public void actionPerformed(ActionEvent arg0) {
this.changeColor();
int currentDelay = p.getDelay() + 20;
this.p.setDelay(currentDelay);
int speed = BASE_SPEED_REFERENCE - currentDelay;
System.out.println(p.getName() + "의 속도--> " + speed);
}
public boolean checkLine(int pos, int value){
if(pos > value) {
System.out.println(this.getText()+"도착!");
return true;
}
return false;
}
public void setMovementType(MovementType type) {
this.movementType = type;
}
public void moveRight(){
int x = this.getLocation().x;
int y = this.getLocation().y;
while(true){
if(checkLine(x, 650) == true || checkLine(10, x) == true) break;
if(BASE_SPEED_REFERENCE - p.getDelay() > 0) x+=10;
else x-=10;
this.setLocation(x, y);
try {
Thread.sleep(p.getDelay());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void moveRandom(){
Random r= new Random();
while(running){
this.changeColor();
System.out.println("망나니 도망 중...");
int x=r.nextInt(800);
int y=r.nextInt(400);
this.changeColor();
this.setLocation(x,y);
try {
Thread.sleep(p.getDelay());
} catch (InterruptedException e) {
e.printStackTrace();
}
}System.out.println("망나니 쓰레드 종료됨!");
}
@Override
public void run() {
switch (movementType) {
case RIGHT : moveRight(); break;
//case DOWN : moveDown(); break;
case RANDOM : moveRandom(); break;
}
}
}
이토록 수정하면 된다!
병아리를 열심히 클릭해보면 속도가 점점 줄어들다가 반대로 이동하는 것을 확인할 수 있다!
...근데 이것도 역시 delay 값을 기본으로 해서 계산하는 것이기 때문에 거북이로 테스트를 해보면 거북이가 거꾸로 가긴 하는데 빨리 가질 못한다!!! 다음에 수정을 한다면 delay 값 처리를 따로 해줘야 할 것 같다...
코드를 따라 치면서 망나니의 checkline 부분을 제거하기도 했다. 망나니인데 선에 닿았다고 멈추면 안 되니까!
코드를 이해하는 데 시간이 좀 많이 걸렸지만 Thread와 GUI에 대해 조금 더 알게 된 것 같아서 의미 있는 시간이었다.
'Develop > Java' 카테고리의 다른 글
| [10주차] SpringBoot - 1 (0) | 2025.11.23 |
|---|---|
| [9주차] DB & JDBC (0) | 2025.11.16 |
| [7주차-2] 디자인패턴 추가조사 - 데코레이터 패턴 (0) | 2025.10.18 |
| [7주차] 디자인패턴 기초실습 (0) | 2025.10.15 |
| [6주차] 커피메이커 v2 리팩토링 (0) | 2025.10.11 |