-
명품자바프로그래밍 13장 실습문제 5번 해답, 정답, 풀이, 해설[자바 Java] 2020. 12. 2. 13:59728x90반응형
사용자가 <ENTER>키를 입력하여 총알을 발사하여 목표물을 맞추는 게임입니다.
제가 작성한 코드 작성 알고리즘은
- 목표물과 총알이 움직이는 속도는 20ms에 5픽셀이므로 목표물 스레드와 총알 스레드에 sleep(20)에 맞춰 5픽셀씩 setLocation 메소드를 호출
- 게임이 시작되면 목표물 스레드인 ChickenThread 시작
- <ENTER>키가 눌리면 총알스레드인 BulletThread가 호출되어 총알 발사
- 총알이 목표물에 맞으면 ChickenThread에 interrupt가 호출되어 ChickenThread가 0.1초 sleep한 후 재개
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154import java.awt.*;import javax.swing.*;import java.awt.event.*;class ChickenThread extends Thread {private JLabel chickenLabel;public ChickenThread(JLabel chickenLabel) {this.chickenLabel=chickenLabel;}@Overridepublic void run() {int i = 5;while(true) {if(chickenLabel.getX()>500) { //오른쪽 화면 밖으로 벗어나면chickenLabel.setLocation(0, chickenLabel.getY());}chickenLabel.setLocation(chickenLabel.getX()+i, chickenLabel.getY());try {Thread.sleep(20); //20ms}catch(InterruptedException e) { //bulletThread에서 hitChicken()하면 interrupt()호출됨chickenLabel.setLocation(0,0); //초기 위치로try {Thread.sleep(100);}catch(InterruptedException f) {return;}}}}}class BulletThread extends Thread {private JLabel bulletLabel;private Thread chickenThread;private JLabel chickenLabel;public BulletThread(JLabel bulletLabel, Thread chickenThread, JLabel chickenLabel) {this.bulletLabel=bulletLabel;this.chickenThread=chickenThread;this.chickenLabel=chickenLabel;}private boolean inChicken(int x, int y) {if(((chickenLabel.getX() < x)&& (chickenLabel.getX() + chickenLabel.getWidth()> x))&&((chickenLabel.getY() < y)&& (chickenLabel.getY() + chickenLabel.getHeight()> y))) {return true;}elsereturn false;}// chickenLabel.getX() < x < chickenLabel.getX()+chickenLabel.getWidth()// chickenLabel.getY() < y < chickenLabel.getY()+chickenLabel.getHeight()private boolean hitChicken() { //bullet의 상단 좌우 점 하나에만 닿으면 HITif(inChicken(bulletLabel.getX(), bulletLabel.getY())||inChicken(bulletLabel.getX()+bulletLabel.getWidth(), bulletLabel.getY())) {return true;}elsereturn false;}@Overridepublic void run() {int i = 5;while(true) {if(hitChicken()) {try {Thread.sleep(100);}catch(InterruptedException e) {return;}chickenThread.interrupt();bulletLabel.setLocation(bulletLabel.getX(), 390); //발사대 위 위치return; //스레드 종료}else {if(bulletLabel.getY()==0) { //위로 넘어가면bulletLabel.setLocation(bulletLabel.getX(), 390); //발사대 위 위치return; //스레드 종료}bulletLabel.setLocation(bulletLabel.getX(), bulletLabel.getY()-i);try {Thread.sleep(20);}catch(InterruptedException e) {return;}}}}}public class ShootChickenGameEx extends JFrame {public ShootChickenGameEx() {setTitle("사격 게임");setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);Container c = getContentPane();c.setFocusable(true);c.requestFocus();c.setLayout(null);ImageIcon chickenImg = new ImageIcon("chicken.png");JLabel chickenLabel = new JLabel(chickenImg);chickenLabel.setSize(85, 85);chickenLabel.setLocation(0,0);c.add(chickenLabel);JLabel bulletLabel = new JLabel();bulletLabel.setSize(15,15);bulletLabel.setOpaque(true);bulletLabel.setBackground(Color.RED);bulletLabel.setLocation(238,390);c.add(bulletLabel);JLabel baseLabel = new JLabel();baseLabel.setSize(60,60);baseLabel.setOpaque(true);baseLabel.setBackground(Color.BLACK);baseLabel.setLocation(215, 405);c.add(baseLabel);setSize(500,500);setVisible(true);setResizable(false);ChickenThread cth = new ChickenThread(chickenLabel);cth.start();c.addKeyListener(new KeyAdapter() {public void keyPressed(KeyEvent e) {if(e.getKeyCode() == KeyEvent.VK_ENTER) {BulletThread bth = new BulletThread(bulletLabel, cth, chickenLabel);if(bulletLabel.getY()==390||bulletLabel.getY()<0) //발사대 위 or 위로 넘어간 경우bth.start();}}});}public static void main(String[] args) {new ShootChickenGameEx();}}cs 총 3개의 Thread를 사용하는 코드를 작성하였습니다.
1. main thread
main()이 담긴 class ShootChickenGameEx
2. ChickenThread
3. BulletThread
main()이 담긴 class ShootChickenGameEx부터 설명하겠습니다.
게임을 진행하면서 키보드 입력을 받아야 하기 때문에 컨테이너에 포커스를 할당합니다.
게임에 사용할 컴포넌트들을 절대위치에 설정하기 위해 배치관리자도 삭제합니다.
치킨이미지와 총알발사대, 총알 모두 JLabel로 작성하였습니다.
절대 위치로 배치한 컴포넌트들 때문에 setResizeable을 false로 하여 게임프레임의 크기를 변경할 수 없도록 합니다.
게임이 시작하면 목표물이 움직이는 ChickenThread가 시작됩니다.
KeyListener는 익명클래스로 작성하여 컨테이너에 부착하였습니다.
키보드의 <ENTER>키가 눌리면 총알을 발사하는 BulletThread를 시작합니다.
총알은 한번에 한 개씩, 목표물을 명중하든지 위로 올라가 실패하여야 다음 발사가 가능하다고 했으므로 if조건문을 만족하여야 BulletThread가 start하도록 작성하였습니다.
BulletThread에서는 총알과 목표물이 명중될 경우를 포함하여 작성하였기 때문에 parameter로 bulletLabel, chickenThread, chickenLabel을 넘겨받습니다.
ChickenThread는 목표물인 ChickenLabel을 움직입니다.
while 무한루프를 돌면서 20ms당 5픽셀 씩 움직이도록 setLocation함수를 사용했습니다.
총알과 목표물이 맞는 경우 BulletThread에서 ChickenThread의 interrupt를 발생시킵니다.
interrupt가 발생하면 ChickenLabel은 초기위치인 좌상단 (0,0)으로 이동하며 잠시 멈춘 후 게임은 계속 진행됩니다.
BulletThread는 parameter로 bulletLabel, chickenThread, chickenLabel을 넘겨받습니다.
BulletThread의 함수로 점 (x,y)가 chickenLabel에 포함되는지 판별하는 함수 inChicken()을 작성하였습니다. hitChicken() 함수에서 inChicken()함수에 bulletLabel의 좌표를 넣고 hit 여부를 판단합니다.
run() 메소드에서는 bulletLabel의 이동을 위해 hit하지 않은 경우 setLocation()과 sleep메소드로 총알을 이동시킵니다.
총알이 명중하지 못하고 위로 넘어간 경우 다음 엔터키가 입력되어 총알을 발사할때까지 기다려야 하므로 break문으로 while루프를 탈출하고 bulletThread는 스스로 종료합니다.
총알이 목표물에 명중한 경우 chickenThread에 interrupt를 호출한 후 총알이 발사대 위 위치로 다시 설정한 후 스레드를 종료합니다.
출판사 제공 답안
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159import java.awt.*;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import javax.swing.*;public class BulletGameFrame extends JFrame{public BulletGameFrame() {setTitle("사격 게임");setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);GamePanel p = new GamePanel();setContentPane(p);setSize(300,300);setResizable(false);setVisible(true);p.startGame();}public static void main(String [] args) {new BulletGameFrame();}}class GamePanel extends JPanel {TargetThread targetThread=null;JLabel baseLabel = new JLabel();JLabel bulletLabel = new JLabel();JLabel targetLabel;public GamePanel() {setLayout(null);baseLabel.setSize(40,40);baseLabel.setOpaque(true);baseLabel.setBackground(Color.BLACK);ImageIcon img = new ImageIcon("images/chicken.jpg");targetLabel = new JLabel(img);targetLabel.setSize(img.getIconWidth(),img.getIconWidth());bulletLabel.setSize(10,10);bulletLabel.setOpaque(true);bulletLabel.setBackground(Color.RED);add(baseLabel);add(targetLabel);add(bulletLabel);}public void startGame() {baseLabel.setLocation(this.getWidth()/2-20, this.getHeight()-40);bulletLabel.setLocation(this.getWidth()/2 - 5, this.getHeight()-50);targetLabel.setLocation(0, 0);targetThread = new TargetThread(targetLabel);targetThread.start();baseLabel.requestFocus();baseLabel.addKeyListener(new KeyAdapter() {BulletThread bulletThread = null;public void keyPressed(KeyEvent e) {if(e.getKeyChar() == '\n') {if(bulletThread==null || !bulletThread.isAlive()) {bulletThread = new BulletThread(bulletLabel, targetLabel, targetThread);bulletThread.start();}}}});}class TargetThread extends Thread {JComponent target;public TargetThread(JComponent target) {this.target = target;target.setLocation(0, 0);target.getParent().repaint();}public void run() {while(true) {int x = target.getX()+5;int y = target.getY();if(x > GamePanel.this.getWidth())target.setLocation(0,0);elsetarget.setLocation(x, y);target.getParent().repaint();try {sleep(20);}catch(InterruptedException e) {// the case of hit by a bullettarget.setLocation(0, 0);target.getParent().repaint();try {sleep(500); // 0.5초 기다린 후에 계속한다.}catch(InterruptedException e2) {}}}}}class BulletThread extends Thread {JComponent bullet, target;Thread targetThread;public BulletThread(JComponent bullet, JComponent target, Thread targetThread) {this.bullet = bullet;this.target = target;this.targetThread = targetThread;}public void run() {while(true) {// 명중하였는지 확인if(hit()) {targetThread.interrupt();bullet.setLocation(bullet.getParent().getWidth()/2 - 5, bullet.getParent().getHeight()-50);return;}else {int x = bullet.getX() ;int y = bullet.getY() - 5;if(y < 0) {bullet.setLocation(bullet.getParent().getWidth()/2 - 5, bullet.getParent().getHeight()-50);bullet.getParent().repaint();return; // thread ends}bullet.setLocation(x, y);bullet.getParent().repaint();}try {sleep(20);}catch(InterruptedException e) {}}}private boolean hit() {if(targetContains(bullet.getX(), bullet.getY()) ||targetContains(bullet.getX() + bullet.getWidth() - 1, bullet.getY()) ||targetContains(bullet.getX() + bullet.getWidth() - 1, bullet.getY()+bullet.getHeight() - 1) ||targetContains(bullet.getX(), bullet.getY()+bullet.getHeight() - 1))return true;elsereturn false;}private boolean targetContains(int x, int y) {if(((target.getX() <= x) && (target.getX() + target.getWidth() - 1 >= x)) &&((target.getY() <= y)&& (target.getY() + target.getHeight() - 1 >= y))) {return true;}elsereturn false;}}}cs 728x90반응형'[자바 Java]' 카테고리의 다른 글
[인프런 김영한의 실전 자바 - 기본편] 000 구매 (0) 2024.01.22 자바 스윙 JTextArea 크기 변경 자유롭게 Resizeable (0) 2020.09.28