Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- 인텔리제이 한글 깨짐 해결법
- 상수
- Java
- function
- for문
- 접근제어지시자
- break문
- java변수
- 반복문
- this예약어
- 컴파일
- JAVA객체지향
- 형 변환
- 인텔리제이 기초 설정
- OPP개념
- 포함관계
- 자바 멀티스레딩
- continue문
- 생성자
- JAVA기초
- While
- 집합관계
- 메서드
- 시스템 환경 변수 편집
- multi-threading
- IntelliJ IDEA
- 연관관계
- Thread
- 메서드 오버로딩
- Java데이터 타입
Archives
- Today
- Total
최원종의 개발 블로그
Bubble_5(물방울 동작 처리) 본문
파일 구성
bubble/test05/
├── Moveable.java ← bubble-1 과 동일
├── PlayerWay.java ← 신규 (enum - 방향 상태)
├── Player.java ← playerWay 필드 추가, 람다식으로 Thread 변경
├── Bubble.java ← Moveable 구현, 이동 로직 추가
├── BackgroundPlayerService.java ← bubble-3 과 동일
└── BubbleFrame.java ← bubble-4 와 동일
package test05;
/**
* [enum] 플레이어의 방향 상태
*
* enum 을 사용하는 이유:
* - boolean 두 개(isLeft, isRight)로 방향을 관리하면
* 둘 다 true 가 되는 잘못된 상태가 생길 수 있음
* enum은 정해진 값 중 하나만 가질 수 있어서 안전함
*
* 사용방법:
* playerWay = PlayerWay.LEFT //값 설정
* if(playerWay == PlayerWay.LEFT) {} // 값 비교
*
* 왜 사용할까?
* 나의 프로젝트나 논리 안에서 데이터의 범위를 지정하고 싶을 때 사용한다
*/
public enum PlayerWay {
LEFT,RIGHT
}
-인터페이스
package test05;
public interface Moveable {
void left();
void right();
void up();
default void down() {
}
// Adapter 클래스가 너무 많이 생겨서 default 문법을
// 인터페이스에서 사용할 수 있도록 만들어 줬다.
// 즉 default 키워드를 사용하면 인터페이스 안에서 일반 메서드를 선언할 수 있다.
}
-Player
package test05;
import javax.swing.*;
public class Player extends JLabel implements Moveable {
// 플레이어의 현재 좌표 상태 값
private int x;
private int y;
// 좌우 방향 이미지(방향키에 따라서 이미지 전환)
private ImageIcon playerR;
private ImageIcon playerL;
// 속도 상수
private final int SPEED = 4; // 좌우 이동 속도 (픽셀)
private final int JUMP_SPEED = 2; // 점프/낙하 속도
private final int JUMP_HEIGHT = 130; // 점프 최대 높이
// 이동 상태 플래그
// true = 해당 방향으로 이동 중 (while 루프 조건)
// false = 멈춤 (while 루프 탈출 -> Thread 종료)
private boolean left = false;
private boolean right = false;
private boolean up = false;
private boolean down = false;
// 벽 충돌 상태 플래그
private boolean leftWallCrash;
private boolean rightWallCrash;
/**
* 플레이어 현재 방향(enum 타입)
* - left() -> playerWay = PlayerWay.LEFT 변경
* - right() -> playerWay = PlayerWay.Right 변경
*/
private PlayerWay playerWay = PlayerWay.RIGHT; // 게임시작시 오른쪽 바람 봄
/// getter
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
public boolean isLeft() {
return left;
}
public boolean isRight() {
return right;
}
public boolean isUp() {
return up;
}
public boolean isDown() {
return down;
}
public boolean isLeftWallCrash() {
return leftWallCrash;
}
public boolean isRightWallCrash() {
return rightWallCrash;
}
public PlayerWay getPlayerWay() {
return playerWay;
}
/// setter
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setLeft(boolean left) {
this.left = left;
}
public void setRight(boolean right) {
this.right = right;
}
public void setUp(boolean up) {
this.up = up;
}
public void setDown(boolean down) {
this.down = down;
}
public void setLeftWallCrash(boolean leftWallCrash) {
this.leftWallCrash = leftWallCrash;
}
public void setRightWallCrash(boolean rightWallCrash) {
this.rightWallCrash = rightWallCrash;
}
public void setPlayerWay(PlayerWay playerWay) {
this.playerWay = playerWay;
}
public Player() {
initData();
setInitLayout();
}
private void initData() {
playerR = new ImageIcon("img/playerR.png");
playerL = new ImageIcon("img/playerL.png");
}
private void setInitLayout() {
// 캐릭터 초기 위치 설정
x = 55;
y = 535;
setSize(50, 50);
setIcon(playerR); // 초기 방향 설정
setLocation(x, y);
}
@Override
public void left() {
if (left) {
return; // 이미 이동 중이면 중복 Thread 생성 방지
}
playerWay = PlayerWay.LEFT;
left = true;
setIcon(playerL);
new Thread(new Runnable() {
@Override
public void run() {
// left 가 true 인 동안 계속 이동
// keyReleased 에서 setLeft(false) 가 호출이 되면 while 탈출
while (left) {
x = x - SPEED;
setLocation(x, y);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
@Override
public void right() {
if (right) {
return;
}
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) {
throw new RuntimeException(e);
}
}
}
}).start();
}
@Override
public void up() {
// 점프 기능을 어떻게 구현할까?
if(up) {
return;
}
up = true;
new Thread(new Runnable() {
@Override
public void run() {
// 130 / 2 --> 65 반복 65 픽셀 업
for (int i = 0; i < JUMP_HEIGHT / JUMP_SPEED; i++) {
y = y - JUMP_SPEED;
setLocation(x, y);
try {
Thread.sleep(5); // 5ms 간격 (낙하 보다 느리게 설정 낙하 3ms )
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
up = false; // 최고점 도달 하고 -> 점프 상태 해제
down(); // 자동 낙하 시작
}
}).start();
}
@Override
public void down() {
down = true;
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < JUMP_HEIGHT / JUMP_SPEED; i++) {
y = y + JUMP_SPEED;
setLocation(x, y);
try {
Thread.sleep(3); // 5ms 간격 (낙하 보다 느리게 설정 낙하 3ms )
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
down = false;
}
}).start();
}
}
-Bubble
package test05;
import javax.swing.*;
public class Bubble extends JLabel implements Moveable {
private int x;
private int y;
private ImageIcon bubbleIcon;
private Player player;
//버블 이동 상태 플래그
private static final int HORIZONTAL_DISTANCE = 400; // 수평 이동 거리
private static final int BUBBLE_SPEED_MS = 1; // 이동 간격 (ms)
private static final int SCREEN_TOP = 0; // 화면 상단 경계
private boolean leftMoving = false;
private boolean rightMoving = false;
private boolean upMoving = false;
// getter
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
// setter
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
// DI
public Bubble(Player player) {
this.player = player;
initData();
setInitLayout();
bubbleStartThread(); // 생성과 동시에 플레이어 방향 판단해서 바로 이동 시작
}
// 물방울 이동 Thread 시작
public void bubbleStartThread() {
new Thread(new Runnable() {
@Override
public void run() {
if(player.getPlayerWay() == PlayerWay.LEFT) {
left(); // 왼쪽으로 400px 이동 --> 완료 후 --> up() 호출
} else {
right(); // 오른쪽으로 400px 이동 --> 완료 후 --> up() 호출
}
}
}).start();
}
private void initData() {
bubbleIcon = new ImageIcon("img/bubble.png");
}
private void setInitLayout() {
x = player.getX();
y = player.getY();
setIcon(bubbleIcon);
setSize(50, 50);
setLocation(x, y);
setVisible(true);
}
@Override
public void left() {
leftMoving = true;
for (int i = 0; i < HORIZONTAL_DISTANCE; i++) {
x--;
setLocation(x, y);
try {
Thread.sleep(BUBBLE_SPEED_MS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
leftMoving = false;
up(); // 수평이동 완료 후 -> 상승 시작
}
@Override
public void right() {
rightMoving = true;
for (int i = 0; i < HORIZONTAL_DISTANCE; i++) {
x++;
setLocation(x, y);
try {
Thread.sleep(BUBBLE_SPEED_MS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
rightMoving = false;
up(); // 수평 이동 완료 -> 상승 시작
}
@Override
public void up() {
upMoving = true;
while (y > SCREEN_TOP) {
y--;
setLocation(x, y);
try {
Thread.sleep(BUBBLE_SPEED_MS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
upMoving = false;
}
@Override
public void down() {
}
}
'Java > SWING' 카테고리의 다른 글
| Bubble_6(바닥, 층 감지 기능) (0) | 2026.03.20 |
|---|---|
| Bubble_4(물방울 생성) (0) | 2026.03.19 |
| Bubble_3(왼쪽 오른쪽 벽 감지) (0) | 2026.03.19 |
| Bubble_2(이동, 점프) (0) | 2026.03.19 |
| Bubble_1(기본 화면완성) (0) | 2026.03.18 |
