진행상황
물방울로 적을 맞추면 물방울 모양이 적이 가둬진 상태로 변경됩니다.
@Override
public void attack() {
state = 1;
setIcon(bubbled);
mContext.remove(enemy); //메모리에서 사라진다
mContext.repaint();
}
코드를 추가하여 물방울이 닿았을 때 적개체가 사라지도록 하였습니다.
left 메서드에 적과 충돌하면 이동을 멈추고 바로 상승하게 하기 위해 break 를 추가하였습니다.
if((Math.abs(x-enemy.getX()) > 40 && Math.abs(x-enemy.getX())<60) &&
(Math.abs(y-enemy.getY()) > 0 && Math.abs(y-enemy.getY())<50)) {
System.out.println("적군 충돌");
attack();
break;
}

❗이때 문제가 발생합니다.
적 개체는
mContext.remove(enemy);
를 통해 사라졌지만 해당 부분에 물방울이 닿게되면
적이 보이지 않더라도 계속해서 물방울에 적이 가둬집니다.이는 remove 된 적 개체가 가비지 컬렉션으로 가게 되는데 이 가비지 컬렉션은 즉시 비워지지 않기 때문에 일어나는 현상입니다.
가비지 컬렉션이 비워질 때 까지 기다릴 수 없기 때문에 Enemy 클래스 자체에 상태값을 줍니다.
private int state; // 0(살아있다), 1(죽었다)
기본적으로 적 개체는 state = 0 을 갖고, attack 메서드는 enemy.getState() == 0 일 때만 작동하도록 코드를 수정합니다.
attack 메서드도 맞추게 되면 enemy 의 상태를 변경하도록 코드를 추가하였습니다.
@Override
public void attack() {
state = 1;
enemy.setState(1);
setIcon(bubbled);
mContext.remove(enemy); //메모리에서 사라진다
mContext.repaint();
}
이때 적을 가둔 방울은 플레이어가 직접 터트릴 때 사라져야 합니다. (지금은 up 메서드 자체에서 clearBubble 호출하여 방울이 터지고 있음)
up 메서드가 crearBubble 호출할 때 조건을 추가하여 에러를 잡았습니다.
@Override
public void up() {
while(true) {
y--;
setLocation(x, y);
if(backGroundBubbleService.topWall()) {
break;
}
try {
if(state==0) { // 기본
Thread.sleep(1);
}else { // 공격 성공 물방울
Thread.sleep(10);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(state == 0) clearBubble(); // 천장에 버블이 도착하고 나서 3초 후에 메모리에서 소멸
}
적을 가둔 방울은 state = 1
그냥 방울은 state = 0 을 갖습니다.
이를 프로그램이 알고있기 위해서는 방울을 관리하는 list 가 필요합니다.
Player 클래스에서 물방울이 생성될 때 마다
bubbleList
에 추가되도록 코드를 수정합니다. private List<Bubble> bubbleList;
private void initObject() {
playerR = new ImageIcon("image/playerR.png");
playerL = new ImageIcon("image/playerL.png");
bubbleList = new ArrayList<>();
}
@Override
public void attack() {
new Thread(()->{
Bubble bubble = new Bubble(mContext);
mContext.add(bubble);
bubbleList.add(bubble);
System.out.println("방울 시작");
if(playerDirection == playerDirection.LEFT) {
bubble.left();
System.out.println("방울 왼쪽");
}else {
bubble.right();
System.out.println("방울 오른쪽");
}
System.out.println("방울 종료");
}).start();
}
플레이어 자신이 닿았는지 알아야 하기 때문에 BackGroundPlayerService 도 수정을 합니다.
// 1. 버블 충돌 체크
for(int i=0; i<bubbleList.size(); i++) {
if(bubbleList.get(i).getState()==1) {
if((Math.abs(player.getX()-bubbleList.get(i).getX()) < 10) &&
(Math.abs(player.getY()-bubbleList.get(i).getY()) > 0 && Math.abs(player.getY()-bubbleList.get(i).getY())<50)) {
System.out.println("몸통 박치기");
}
}
}
이렇게 실행한 뒤 방울에 플레이어를 부딪히면 설정했던 몸통 박치기 로그가 나옵니다.
Bubble 클래스에 적이 갇힌 물방울을 제거하는 메서드를 추가합니다.
public void clearBubbled() {
try {
up = false;
setIcon(bomb);
Thread.sleep(1000);
mContext.remove(this);
mContext.repaint();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
백그라운드플레이어서비스를 수정하고 실행해 보면 이렇게 작동합니다.
for(int i=0; i<bubbleList.size(); i++) {
Bubble bubble = bubbleList.get(i);
if(bubbleList.get(i).getState()==1) {
if((Math.abs(player.getX()-bubble.getX()) < 10) &&
(Math.abs(player.getY()-bubble.getY()) > 0 && Math.abs(player.getY()-bubble.getY())<50)) {
System.out.println("몸통 박치기");
bubble.clearBubbled();
}
}
}

바닥을 뚫고 아래로 추락하게 됩니다…
아마 crearBubbled 메서드의 repaint 가 작동되는 동안 바닥을 뚫지 못하게 설정해 놓은 코드가 적용되지 않아 발생하는 문제 같아 보입니다.
따라서 crearBubbled 에 별도의 스레드를 적용시켜 코드를 수정하겠습니다.
public void clearBubbled() {
new Thread(()->{
try {
up = false;
setIcon(bomb);
Thread.sleep(1000);
mContext.remove(this);
mContext.repaint();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
이제 BGM 과 적군이 움직이도록 하는 기능만 하면 끝납니다~ 👍

- 게임 맵과 캐릭터 추가 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
- 물방울 공격하기 완료 https://inblog.ai/hj/sts-버블버블-물방울로-공격하기-40303
Share article