지금까지 상태.
- 물방울이 스페이스를 누를 때 마다 생성된다 ( 이때 매번 스레드가 생성되고 해제되지 않음)
- 물방울은 벽을 뚫는다 (좌/우 벽에 닿더라도 그냥 뚫고 화면밖으로 나감)
→ 스레드 문제와 벽 충돌 감지.
→ 물방울이 천장에 닿으면 화면에서 제거.
1. 물방울 충돌 감지
백그라운드 서비스 생성
백그라운드 이미지를 버퍼로 읽는 메서드와
좌,우,상단에 방울이 닿았는지 여부를 리턴하는 메서드를 작성한다.
이 코드는 매번 물방울이 생성 될 때마다 함께 만들어 져야한다.
(하나만 만들어 진다면 다른 방울들은 감지되지 않기 때문이다.)
방울이 만들어 지는 곳은
Bubble.java
의 space 가 눌러질때 마다 생성된다.public class BackGroundBubbleService{
private BufferedImage image;
private Bubble bubble;
public BackGroundBubbleService(Bubble bubble) {
this.bubble = bubble;
try {
image = ImageIO.read(new File("image/backgroundMapservice.png"));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public boolean leftWall() {
return false;
}
public boolean rightWall() {
return false;
}
public boolean topWall() {
return false;
}
}
Bubble 클래스 수정
백그라운드 서비스를 추가한다. player 같은 경우는 스레드로 동작 하지만 bubble 같은 경우는 위에 서술한것 처럼 bubble 이 생성될 때 new 가 되어야 한다.
//의존성 콤포지션
private Player player;
private BackGroundBubbleService backGroundBubbleService;
private void initObject() {
bubble = new ImageIcon("image/bubble.png");
bubbled = new ImageIcon("image/bubbled.png");
bomb = new ImageIcon("image/bomb.png");
backGroundBubbleService = new BackGroundBubbleService(this);
}
@Override
public void left() {
left = true;
for(int i=0; i<400; i++) {
x--;
setLocation(x, y);
if(backGroundBubbleService.leftWall()) {
break;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
up();
}
만약 leftWall 이 true 라면 이동을 멈춰주는 로직을 추가하였다.
BackGroundBubbleService 수정
left 와 right 가 ture 를 리턴받으면 물방울의 움직임은 멈추고 up 만 수행하게 된다.
플레이어때 사용했던 컬러값을 복사해 와서 코드를 수정하였다.
if(leftColor.getRed() == 255 && leftColor.getGreen()==0 && leftColor.getBlue()==0) {
//System.out.println("왼쪽 벽에 충돌함");
player.setLeftWallCrash(true);
player.setLeft(false);
}
public boolean leftWall() {
Color leftColor = new Color(image.getRGB(bubble.getX() - 10, bubble.getY()+ 25));
if(leftColor.getRed() == 255 && leftColor.getGreen()==0 && leftColor.getBlue()==0) {
System.out.println("왼쪽 벽에 충돌함");
return true;
}
return false;
}
플레이어는 움직임을 멈추고 다시 키보드를 사용하여 움직였기 때문에 player 의 상태를 false 로 바꾸었다.
방울의 경우엔 움직임을 멈추라는것만 전달하면 되기 때문에 ture 를 리턴해준다.
(플레이어는 while 로 동작하고 있고, 버블은 for 문이라는 차이도 존재)
실행해 보면 이렇게 벽을 뚫지 않고 잘 실행되는 모습을 볼 수 있다.

상단을 막는 코드도 추가한다.
public boolean topWall() {
Color topColor = new Color(image.getRGB(bubble.getX() + 25, bubble.getY()-10));
if (topColor.getRed() == 255 && topColor.getGreen()==0 && topColor.getBlue()==0) {
System.out.println("업??");
return true;
}
return false;
}
bubble.getX() + 25, bubble.getY()-10 이 부분은 bubble 그림의 어느 부분이 닿았는지 감지하는 역할이기 때문에 바르게 계산하지 않으면 이런식으로 원하지 않는 위치에서 움직임이 멈춰버린다…….

2. 물방울 스레드 해제 및 화면에서 지우기
스레드 해제
천장에 닿으면 3초 뒤 방울을 사라지게 하려고 한다.
@Override
public void up() {
while(true) {
y--;
setLocation(x, y);
if(backGroundBubbleService.topWall()) {
break;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
clearBubble(); // 천장에 버블이 도착하고 나서 3초 후에 메모리에서 소멸
}
private void clearBubble() {
try {
Thread.sleep(3000);
setIcon(bomb);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
clearBubble 메서드에서 일단 3초 뒤 방울 그림을 변경하도록 했다.
의도한대로 코드가 작동하고 있고,
스레드 실행 시작 스레드 실행 완료
완료 메세지는 뜨지만 Pon 이미지가 화면에서 사라지지는 않고 있다.
만약 이미지를 검정색이나 안보이는 것으로 변경 한다면 눈으로는 보이지 않지만
프레임은 계속해서 내가 설정한 이미지를 (눈에 보이지 않더라도) 그리고 있는 상태가 된다.

완전히 이미지를 제거하기 위해서는 프레임 자체를 새로 그려주어야 한다.
프레임을 새롭게 그려주기 위해 Bubble 클래스에 프레임을 가져온다.
그리고 Bubble 이 생성될 때 마다 context 를 생성자로 가진다.
이때 BubbleFrame 클래스는 player 를 갖고 있기 때문에
this.player = player
이 아닌 mContext 에서 가져오도록 코드를 수정하였다. private BubbleFrame mContext;
public Bubble(BubbleFrame mContext) {
this.mContext = mContext;
this.player = mContext.getPlayer();
initObject();
initSetting();
initThread();
}
이렇게 했을 때 BubbleFrame 의 코드에서 에러가 발생한다.
기존에 했던것 처럼 Bubble 이 생성될 때 생성자로 player 가 아닌 mContext
즉, 본인의 입장에서 this 를 받아야 하기 때문이다.
case KeyEvent.VK_SPACE:
Bubble bubble = new Bubble(player);
add(bubble);
break;
}
case KeyEvent.VK_SPACE:
Bubble bubble = new Bubble(this);
add(bubble);
break;
}
그러나 해당 코드에서 this 를 작성하게 되면
BubbleFrame 이 아닌 해당 메서드가 this 에 해당하기 때문에
mContext
를 생성자로 받아야 하고 case KeyEvent.VK_SPACE:
Bubble bubble = new Bubble(mContext);
add(bubble);
break;
}
private BubbleFrame mContext = this;
this 는 mContext 임을 명시해 준다.

이를 통해 생성된 Bubble 은 프레임의 정보를 갖게 된다.(this 사용이 가능해짐)
private void clearBubble() {
try {
Thread.sleep(3000);
setIcon(bomb);
Thread.sleep(500);
mContext.remove(this); // BubbleFrame 의 메모리에서 사라짐
mContext.repaint();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
실행을 시켜보면 다음과 같이 잘 작동한다.

스레드를 사용하여 만들어진 bubble 은 left, right 메서드를 호출하고 나면 동작이 완료된다.
그러나 만들어져서 화면에 남아있는 Bubble 들은 프레임을 다시 그리지 않는 한 계속해서 화면에 남아있게 된다.
해결하기 위해
BubbleFrame
을 사용하여 Bubble 을 메모리에서 해제시킬 수 있다.
방법은 bubble이 생성될 때 Player 가 아닌 BubbleFrame 을 생성자로 주입받는 것이다.이 과정을 통해 방울은 화면에에 생성되고 삭제될 수 있다.
- 게임 맵과 캐릭터 추가 https://inblog.ai/hj/sts-버블버블-게임-맵과-캐릭터-추가하기-33126
- 스레드 사용하여 이동하기 https://inblog.ai/hj/sts-버블버블-스레드-사용이동-33335
- 외벽 충돌 시 캐릭터 정지 https://inblog.ai/hj/sts-버블버블-외벽-충돌-시-캐릭터-정지-36946
- 캐릭터 업 다운 시키기 https://inblog.ai/hj/sts-버블버블-캐릭터-업-다운-38143
- 물방울 생성하기(기본셋팅) https://inblog.ai/hj/sts-버블버블-물방울-기본-셋팅-38154
- 물방울 움직이게 하기 https://inblog.ai/hj/sts-버블버블-물방울-움직이게-하기-38195
- 물방울 메모리에서 해제 하고 화면 다시 그리기 https://inblog.ai/hj/sts-버블버블-물방울-완성하기-38589
- 리팩토링 하기
- 적군 만들기
Share article