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데이터 타입
- 연관관계
- 자바 멀티스레딩
- 시스템 환경 변수 편집
- 집합관계
- While
- 포함관계
- JAVA기초
- this예약어
- IntelliJ IDEA
- 메서드 오버로딩
- 생성자
- continue문
- 메서드
- Java
- 형 변환
- OPP개념
- for문
- 상수
- 컴파일
- JAVA객체지향
- 인텔리제이 기초 설정
- 접근제어지시자
- 인텔리제이 한글 깨짐 해결법
- Thread
- 반복문
- java변수
- break문
- function
- multi-threading
Archives
- Today
- Total
최원종의 개발 블로그
Bubble_6(바닥, 층 감지 기능) 본문
bubble/test05/
├── Moveable.java ← bubble-1 과 동일
├── PlayerWay.java ← bubble-5와 동일
├── Player.java ← playerWay 필드 추가, 람다식으로 Thread 변경
├── Bubble.java ← bubble-5와 동일
├── BackgroundPlayerService.java ← 발판 색상 감지
└── BubbleFrame.java ← bubble-4와 동일
배경에 있는 색상을 이용해 벽과 바닥 층 색상을 감지해 플레이어의 위치를 고정시킴.


-코드
package test06;
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();
}
/**
* 낙하 변경(중력)
* for -> while(down) 으로 변경
* while(true) --> (down)
* BackgroundPlayerService 가 바닥 감시
* setDown(false) 호출 --> down 상태 값을 false 변경 한다면 while(down) 이 종료 -> 낙하 종료
*/
@Override
public void down() {
down = true;
new Thread(new Runnable() {
@Override
public void run() {
while (down) {
y += JUMP_SPEED;
setLocation(x, y);
try {
Thread.sleep(3);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}).start();
}
}
-BackgroundPlayerService
package test06;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
/**
* [클래스 역할] - 플레이어 충돌 감지 서비스(백그라운드에서 계속 돌아감) - 메인 쓰레드는 너무 바쁨
*/
public class BackgroundPlayerService implements Runnable {
// ImageIcon / Image
// 화면에 그려서 보여주기 위한 이미지
// --> 픽셀 데이터에 직접 접근이 불가능 함
// BufferedImage
// --> 메모리에 픽셀 배열로 저장된 이미지
// --> getRGB(x, y)로 특정 좌표의 색상값을 직접 읽을 수 있음
private BufferedImage image;
private Player player;
// 의존성 주입 DI(Dependency Injection)
// player 를 생성자를 통해서 외부에서 주입 받음
// 즉, 이 서비스가 직접 플레이어를 생성하지 않고 외부에서 주입 받아 사용 됨.
public BackgroundPlayerService(Player player) {
this.player = player;
try {
image = ImageIO.read(new File("img/backgroundMapService.png"));
} catch (IOException e) {
throw new RuntimeException(" 충돌 감지 이미지를 찾을 수 없습니다 " + e);
}
}
@Override
public void run() {
// 게임 끝날 때 까지 계속 실행 되어야 함.
while (true) {
Color leftColor = new Color(image.getRGB(player.getX(), player.getY() + 25));
Color rightColor = new Color(image.getRGB(player.getX() + 60, player.getY() + 25));
// 바닥/층 감지 좌표 (플레이어 발 아래 두점)
int bottomLeft = image.getRGB(player.getX() + 20, player.getY() + 55);
int bottomRight = image.getRGB(player.getX() + 50, player.getY() + 55);
System.out.println("bottomLeft : " + bottomLeft);
System.out.println("bottomRight : " + bottomRight);
if (bottomLeft + bottomRight == -2) {
// 계속 낙하 시킬 예정
// 발 아래가 허공 -> 아직 점프/낙하 중이 아닐 때만 낙하 시작해야 함
// player.isUp() == false -> 점프 중이 아님
// player.isDown() == false -> 낙하 중이 아님
if (player.isUp() == false && player.isDown() == false) {
player.down();
}
} else {
// 발 아래가 바닥/ 층 -> 낙하 즉시 중단
player.setDown(false); // while(down) --> false -> while 종료 , Thread 종료
}
// 정수 값 - 1 면 흰색
// 정수 값 -65536 면 빨간색
// 왼쪽 벽 충돌 감지 판단
if (isRed(leftColor)) {
// 충돌 상태 변수 ON
player.setLeftWallCrash(true);
player.setLeft(false); // while(false) 종료 --> 이동 멈춤 (Thread 종료)
} else {
// 벽에서 벗어나면 즉시 해제 --> 다시 이동 가능하게 설정
player.setLeftWallCrash(false);
}
// 오른쪽 벽 충돌 감지 판단
if (isRed(rightColor)) {
// 충돌 상태 변수 ON
player.setRightWallCrash(true); // 충돌 상태 ON
player.setRight(false); // while(right) 종료 --> 이동 멈춤 Thread 종료
} else {
player.setRightWallCrash(false); // 벽에서 벗어나면 즉시 해제
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// 255, 0 , 0 -> 빨간색
private boolean isRed(Color color) {
return color.getRed() == 255
&& color.getGreen() == 0
&& color.getBlue() == 0;
}
}
'Java > SWING' 카테고리의 다른 글
| Bubble_5(물방울 동작 처리) (0) | 2026.03.19 |
|---|---|
| Bubble_4(물방울 생성) (0) | 2026.03.19 |
| Bubble_3(왼쪽 오른쪽 벽 감지) (0) | 2026.03.19 |
| Bubble_2(이동, 점프) (0) | 2026.03.19 |
| Bubble_1(기본 화면완성) (0) | 2026.03.18 |
