- [Java] 74. Swing: 버블버블 게임 만들기(5)2024년 05월 03일
- Song hyun
- 작성자
- 2024.05.03.:50
728x90반응형[Java] 74. Swing: 버블버블 게임 만들기(5)
이전 글: https://whatsthatsound.tistory.com/132
https://whatsthatsound.tistory.com/133
https://whatsthatsound.tistory.com/134
https://whatsthatsound.tistory.com/138
1. 목차
자바의 GUI Swing을 사용해 이전의 코드를 보완해보자.
2. 구현해야 할 동작들
3. 코드 블록
(1) Bubble : 버블 클래스 및 메서드 생성
(2) BackgroundPlayerService: 플레이어의 움직임 관찰 & 제어 쓰레드 생성!
(3) BubbleFrame : 프레임 / 키 이벤트 / 시범 실행
(4) Player : player 객체 및 메서드 생성 (moveable 구현), 움직임 쓰레드 구현(Run-Start)
(5) Moveable : 인터페이스
package BubbleBubble.test.ex07; import javax.swing.ImageIcon; import javax.swing.JLabel; public class Bubble extends JLabel implements Moveable { private Player player; private int x; private int y; // 움직임 상태 private boolean left; private boolean right; private boolean up; // 적군을 맞춘 상태 private int state; // 0. 기본 물방울 1. 적을 가둔 상태 물방울 private ImageIcon bubble; // 기본 물방울 private ImageIcon bubbled; // 적을 가둔 물방울 private ImageIcon bomb; // 물방울 팡! // 연관 관계, 의존성 컴포지션 관계, 생성자 의존 주입(Dependency Injection) public Bubble(Player player) { this.player = player; initData(); setInitLayout(); // 객체 생성시 무조건 스레드 시작 initThread(); } // Getter, Setter 메서드 public Player getPlayer() { return player; } public void setPlayer(Player player) { this.player = player; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public boolean isLeft() { return left; } public void setLeft(boolean left) { this.left = left; } public boolean isRight() { return right; } public void setRight(boolean right) { this.right = right; } public boolean isUp() { return up; } public void setUp(boolean up) { this.up = up; } public int getState() { return state; } public void setState(int state) { this.state = state; } public ImageIcon getBubble() { return bubble; } public void setBubble(ImageIcon bubble) { this.bubble = bubble; } public ImageIcon getBubbled() { return bubbled; } public void setBubbled(ImageIcon bubbled) { this.bubbled = bubbled; } public ImageIcon getBomb() { return bomb; } public void setBomb(ImageIcon bomb) { this.bomb = bomb; } private void initData() { bubble = new ImageIcon("img/bubble.png"); bubbled = new ImageIcon("img/bubbled.png"); bomb = new ImageIcon("img/bomb.png"); left = false; right = false; up = false; state = 0; } private void setInitLayout() { x = player.getX(); y = player.getY(); setIcon(bubble); setSize(50, 50); setLocation(x, y); } // 공통으로 사용하는 부분을 메서드로 만들어보자. // 이 메서드는 내부에서만 사용할 예정. private void initThread() { // 버블은 스레드가 하나면 된다. // 익명 클래스, 익명 구현 클래스 new Thread(new Runnable() { public void run() { if (player.playerWay == PlayerWay.LEFT) { left(); } else { right(); } } }).start(); } @Override public void left() { left = true; for (int i = 0; i < 400; i++) { x--; setLocation(x, y); try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } up(); // TODO Auto-generated method stub } @Override public void right() { right = true; for (int i = 0; i < 400; i++) { x++; setLocation(x, y); try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } up(); // TODO Auto-generated method stub } @Override public void up() { up = true; while (true) { y--; setLocation(x, y); try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
package BubbleBubble.test.ex07; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; /* * 현재 메인 쓰레드는 너~무 바빠! * 그래서, 백그라운드에서 계속 플레이어의 움직임을 관찰할 예정. */ public class BackgroundPlayerService implements Runnable { private BufferedImage image; private Player player; // 생성자 의존 설계 (Dependency Injection) public BackgroundPlayerService(Player player) { this.player = player; try { image = ImageIO.read(new File("img/backgroundMapService.png")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void run() { // 색상 확인 todo(보정값 필요) while (true) { Color leftColor = new Color(image.getRGB(player.getX() + 10+5, player.getY() + 25)); Color rightColor = new Color(image.getRGB(player.getX() + 50 +10, player.getY() + 25)); // Color bottomColor = new Color(image.getRGB(player.getX(), player.getY())); // 흰색이면 바닥 RGB 값이 == 255, 255, 255 // 바닥인 경우는 --> 255, 0, 0 (=바닥) // 바닥인 경우는 --> 0, 0, 255 (=바닥) int bottomColorLeft = image.getRGB(player.getX() + 20, player.getY() + 50+5); int bottomColorRight = image.getRGB(player.getX() - 40, player.getY() + 50 + 5); // 하얀색 --> -1 if ((bottomColorLeft + bottomColorRight) != -2) { // 여기는 멈춰야 한다. (즉, 빨간 바닥 혹은 파란 바닥) player.setDown(false); } else { // 점프하는 순간에는 다운되면 안 된다. // 플레이어가 올라가는 상황이 아니라면, // 플레이어가 내려가는 상황이 아니라면, --> Down 호출 if (!player.isUp() && !player.isDown()) { player.down(); } } // 왼쪽에 충돌함 if (leftColor.getRed() == 255 && leftColor.getGreen() == 0 && leftColor.getBlue() == 0) { System.out.println("왼쪽 벽에 충돌함."); player.setLeftWallCrash(true); player.setLeft(false); } else if (rightColor.getRed() == 255 && rightColor.getGreen() == 0 && rightColor.getBlue() == 0) { System.out.println("오른쪽 벽에 충돌함."); player.setRightWallCrash(true); player.setRight(false); } else { player.setLeftWallCrash(false); player.setRightWallCrash(false); } // 위 두 조건이 아니면 player 마음대로 움직일 수 있다. try { Thread.sleep(3); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
package BubbleBubble.test.ex07; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.ImageIcon; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; public class BubbleFrame extends JFrame { private JLabel backgroundMap; private Player player; public BubbleFrame() { initData(); setInitLayout(); addEventListener(); // Player 백그라운드 서비스 시작 new Thread(new BackgroundPlayerService(player)).start(); } private void initData() { // todo-이미지 변경 backgroundMap = new JLabel(new ImageIcon("img/backgroundMap.png")); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Frame --> root Panel setContentPane(backgroundMap); setSize(1000, 640); player = new Player(); } private void setInitLayout() { // 좌표값으로 배치 setLayout(null); setResizable(false); // 프레임 조절 불가 setLocationRelativeTo(null); // JFrame을 여러분 모니터 가운데에 자동 배치 setVisible(true); add(player); } private void makeBubble(Player player) { Bubble bubble = new Bubble(player); add(bubble); } private void addEventListener() { this.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { System.out.println("key code : " + e.getKeyCode()); switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: // 왼쪽으로 방향키를 누르고 있다면, // 키보드 이벤트가 계속 왼쪽으로 간다. <- <- <- // 왼쪽 상태가 아니라면,? if(!player.isLeft() && !player.isLeftWallCrash()) { player.left(); } // 왼쪽 벽에 충돌한 게 아니라면,? break; case KeyEvent.VK_RIGHT: if(!player.isRight() && !player.isRightWallCrash()) { player.right(); } break; case KeyEvent.VK_UP: player.up(); break; case KeyEvent.VK_SPACE: makeBubble(player); // 내가 짠 코드 add(new Bubble(player)); // 선생님이 짜신 코드 default: break; } } // end of key pressed @Override public void keyReleased(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: // 왼쪽으로 가는 거 멈춰! player.setLeft(false); break; case KeyEvent.VK_RIGHT: // 오른쪽으로 가는 거 멈춰! player.setRight(false); break; case KeyEvent.VK_UP: player.setUp(false); break; default: break; } } // end of keyReleased }); // end of keyAdapter } // 코드 테스트 public static void main(String[] args) { new BubbleFrame(); } }
package BubbleBubble.test.ex07; import javax.swing.ImageIcon; import javax.swing.JLabel; public class Player extends JLabel implements Moveable { private int x; private int y; private ImageIcon playerR, playerL; // 움직임의 상태 private boolean left; private boolean right; private boolean up; private boolean down; // 벽에 충돌한 상태 private boolean leftWallCrash; private boolean rightWallCrash; // 플레이어 속도 상태 private final int SPEED = 4; private final int JUMPSPEED = 2; // enum 타입의 활용 PlayerWay playerWay; // get, set // setter 메서드 public void setLeft(boolean left) { this.left = left; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public ImageIcon getPlayerR() { return playerR; } public void setPlayerR(ImageIcon playerR) { this.playerR = playerR; } public ImageIcon getPlayerL() { return playerL; } public void setPlayerL(ImageIcon playerL) { this.playerL = playerL; } public boolean isDown() { return down; } public void setDown(boolean down) { this.down = down; } public boolean isLeftWallCrash() { return leftWallCrash; } public void setLeftWallCrash(boolean leftWallCrash) { this.leftWallCrash = leftWallCrash; } public boolean isRightWallCrash() { return rightWallCrash; } public void setRightWallCrash(boolean rightWallCrash) { this.rightWallCrash = rightWallCrash; } public boolean isLeft() { return left; } public boolean isRight() { return right; } public boolean isUp() { return up; } public int getSPEED() { return SPEED; } public int getJUMPSPEED() { return JUMPSPEED; } public void setRight(boolean right) { this.right = right; } public void setUp(boolean up) { this.up = up; } public Player() { initData(); setInitLayout(); } private void initData() { playerR = new ImageIcon("img/playerR.png"); playerL = new ImageIcon("img/playerL.png"); // 처음 실행 시 초기 값 셋팅 x = 450; y = 540; leftWallCrash = false; rightWallCrash = false; playerWay = PlayerWay.RIGHT; // 플레이어가 가만히 멈춘 상태 left = false; right = false; up = false; down = false; setIcon(playerR); this.setSize(50, 50); setLocation(x, y); } private void setInitLayout() { } @Override public void left() { playerWay = PlayerWay.LEFT; left = true; setIcon(playerL); new Thread(new Runnable() { @Override public void run() { while (left) { x = x - SPEED; setLocation(x, y); try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // end of while } // end of run }).start(); // end of Thread } @Override public void right() { playerWay = PlayerWay.RIGHT; right = true; setIcon(playerR); new Thread(new Runnable() { @Override public void run() { while (right) { x = x + SPEED; setLocation(x, y); try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // end of while } // end of run }).start(); // end of Rannable } // end of right @Override public void up() { System.out.println("점프"); up = true; new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 130 / JUMPSPEED; i++) { y = y - JUMPSPEED; setLocation(x, y); try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } // end of for up = false; down(); } // end of run }).start(); // 객체의 상태값을 잘 조절해야 한다. } @Override public void down() { System.out.println("다운"); down = true; new Thread(new Runnable() { public void run() { while (down) { y = y + SPEED; setLocation(x, y); try { Thread.sleep(3); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } down = false; } }).start(); } }
package BubbleBubble.test.ex07; public enum PlayerWay { LEFT,RIGHT }
728x90반응형'Java > 기본 개념 및 클래스' 카테고리의 다른 글
[Java] 76. Thread 메서드: wait/notify (0) 2024.05.13 [Java] 75. Swing: 버블버블 게임 만들기(6) (0) 2024.05.07 [Java] 69. 멀티 스레딩의 개념과 동기화 (0) 2024.05.01 [Java] 68. 메모리 상에서의 스레드 (0) 2024.05.01 [Java] 67. 쓰레드의 개념과 사용 방법 (0) 2024.05.01 다음글이전글이전 글이 없습니다.댓글
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)