[STS] 버블버블 - 물방울로 공격하기

HootJem's avatar
Jan 14, 2025
[STS] 버블버블 - 물방울로 공격하기
진행상황
물방울로 적을 맞추면 물방울 모양이 적이 가둬진 상태로 변경됩니다.
 
@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; }
notion image
 
❗이때 문제가 발생합니다.
적 개체는 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(); } } }
notion image
바닥을 뚫고 아래로 추락하게 됩니다…
아마 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 과 적군이 움직이도록 하는 기능만 하면 끝납니다~ 👍
notion image
 
Share article

[HootJem] 개발 기록 블로그