[명품자바] 13장 오픈 챌린지

sum·2022년 6월 13일
0

아바타와 괴물 게임 만들기

아바타와 괴물이 등장하고 괴물은 터미네이터처럼 끊임없이 아바타를 따라다니는 게임을 만들어보자. 아바타는 15x15 크기의 "@" 문자열 레이블로 만들고, 괴물 역시 "M" 문자열 레이블로 만든다. 아바타는 상하좌우 키를 이용하여 패널상에서 움직이면서 도망가고, 괴물은 자동으로 아바타를 추적하여 따라다닌다. 아바타가 도망치는 속도가 떨어지면 괴물에게 잡히게 된다. 이 게임은 점수를 관리하지 않는다. 오직 'q' 키를 입력해야 게임은 종료된다. 아바타는 한 번의 키 입력에 따라 10픽셀씩 이동하며, 괴물은 상하좌우대각선 방향으로 움직일 수 있고 200ms마다 한 번 이동하고 그 거리는 5픽셀이다.

힌트

  • 컨텐트팬으로 사용할 GamePanel을 만들고 이곳에서 아바타 레이블과 괴물 레이블이 자유롭게 위치할 수 있도록 배치관리자를 삭제한다.
  • KeyListener를 구현하여 GamePanel에 등록한다. keyPressed() 메소드를 작성하고 먼저 KeyEvent.getKeyChar() 메소드를 호출하여 'q' 키가 입력되었는지 비교하고 그렇다면 System.exit(0)을 호출하여 프로그램을 종료한다. 다시 KeyEvent.getKeyCode() 메소드를 호출하여 상하좌우 키의 가상 키 값과 비교한다.
  • GamePanel이 키 입력을 받을 수 있도록 포커스를 주는 것을 잊지 말라.
  • Thread를 상속받은 MonsterThread 스레드를 작성하고 run() 메소드에서 4가지 경우를 판단한다. 아바타가 괴물의 왼쪽에 있는지, 오른쪽에 있는지, 위쪽에 있는지, 아래쪽에 있는지 판단하고 그에 따라 괴물의 위치를 조정한다. 괴물의 위치가 변경되면 곧장 GamePanel을 다시 그려야 한다. 예를 들어 괴물 레이블이 monster이면 moster.getParent().repaint()를 호출한다.

코드

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class GamePanel extends JPanel {
    private JLabel avatar = new JLabel("@");
    private JLabel monster = new JLabel("M");

    int avatarX = 100;
    int avatarY = 100;
    int monsterX = 200;
    int monsterY = 200;

    public GamePanel() {
        setLayout(null); //배치관리자 삭제
        avatar.setForeground(Color.RED);

        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {

                //방향키
                int key = e.getKeyCode();
                if(key == KeyEvent.VK_UP) {//상
                    avatarY -= 10;
                } else if (key == KeyEvent.VK_DOWN) {//하
                    avatarY += 10;
                } else if (key == KeyEvent.VK_LEFT) {//좌
                    avatarX -= 10;
                } else {//우
                    avatarX += 10;
                }

                int keyChar = e.getKeyChar();
                if(keyChar == 'q')
                    System.exit(0);
                repaint();
            }
        });
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        avatar.setSize(15,15);
        avatar.setLocation(avatarX,avatarY);
        add(avatar);

        monster.setSize(15,15);
        monster.setLocation(monsterX,monsterY);
        add(monster);
    }
}

class MonsterThread extends Thread {
    private GamePanel p;

    public MonsterThread(GamePanel panel) {
        p = panel;
    }

    public void run() {
        while (true) {
            if(p.avatarX < p.monsterX) { //아바타가 왼쪽에 있으면
                p.monsterX -= 5;
            } else if (p.avatarX > p.monsterX) {//아바타가 오른쪽에 있으면
                p.monsterX += 5;
            }

            if (p.avatarY < p.monsterY) {//아바타가 위쪽에 있으면
                p.monsterY -= 5;
            } else if (p.avatarY > p.monsterY) {//아바타가 아래쪽에 있으면
                p.monsterY += 5;
            }

            p.repaint(); //몬스터 움직임

            try {
                sleep(200);
            } catch (InterruptedException e) {
                return;
            }
        }
    }
}
public class AvatarAndMonsterGame extends JFrame{
    public AvatarAndMonsterGame() {
        setTitle("아바타와 괴물 게임");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GamePanel panel = new GamePanel();
        setContentPane(panel);
        panel.setFocusable(true);
        panel.requestFocus(); //GamePanel이 키 입력을 받을 수 있도록 포커스 주기

        setSize(300,300);
        setVisible(true);

        MonsterThread th = new MonsterThread(panel);
        th.start();
    }
    public static void main(String[] args) {
        new AvatarAndMonsterGame();
    }
}

출력


0개의 댓글