목표
1. 적군 클래스 설계
2. 태어나자 마자 움직이게 함
3. 적군이 버블에 맞으면 버블에 갇힘 → 천장 까지 상승
4. 바닥에서만 움직이도록 자연스럽게
package bubble.components;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import bubble.BubbleFrame;
import bubble.interfaces.Moveable;
import bubble.service.BackgroundEnemyService;
import bubble.state.EnemyWay;
public class Enemy extends JLabel implements Moveable {
BubbleFrame mContext;
// 살아 있는 상태 0, 물방울에 갇힌 상태 1
private int state;
private int x;
private int y;
private ImageIcon enemyR, enemyL;
// 적군 움직임의 상태
private boolean left;
private boolean right;
private boolean up;
private boolean down;
// 바닥의 끝에 도달한 상태
private boolean whiteBottom;
// 적군 속도 상태
private final int SPEED = 3;
private final int JUMPSPEED = 1;
// 적군 방향 상태
private EnemyWay enemyWay;
// get, set
// 적군 크기
private final int E_WIDTH = 50;
private final int E_HEIGTH = 50;
// setter
public void setLeft(boolean left) {
this.left = left;
}
public void setRight(boolean right) {
this.right = right;
}
public Enemy(BubbleFrame mContext) {
this.mContext = mContext;
initData();
setInitLayout();
new Thread(new BackgroundEnemyService(this)).start();
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public BubbleFrame getmContext() {
return mContext;
}
public void setmContext(BubbleFrame mContext) {
this.mContext = mContext;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public ImageIcon getEnemyR() {
return enemyR;
}
public void setEnemyR(ImageIcon enemyR) {
this.enemyR = enemyR;
}
public ImageIcon getEnemyL() {
return enemyL;
}
public void setEnemyL(ImageIcon enemyL) {
this.enemyL = enemyL;
}
public boolean isUp() {
return up;
}
public void setUp(boolean up) {
this.up = up;
}
public boolean isDown() {
return down;
}
public void setDown(boolean down) {
this.down = down;
}
public EnemyWay getEnemyWay() {
return enemyWay;
}
public void setEnemyWay(EnemyWay enemyWay) {
this.enemyWay = enemyWay;
}
public boolean isLeft() {
return left;
}
public boolean isRight() {
return right;
}
public int getSPEED() {
return SPEED;
}
public int getJUMPSPEED() {
return JUMPSPEED;
}
public int getE_WIDTH() {
return E_WIDTH;
}
public int getE_HEIGTH() {
return E_HEIGTH;
}
public boolean isWhiteBottom() {
return whiteBottom;
}
public void setWhiteBottom(boolean whiteBottom) {
this.whiteBottom = whiteBottom;
}
private void initData() {
enemyR = new ImageIcon("img/enemyR.png");
enemyL = new ImageIcon("img/enemyL.png");
state = 0;
// 처음 실행 시 초기 값 세팅
x = 720;
y = 175;
// 플레이어가 가만히 멈춘 상태
left = false;
right = false;
up = false;
down = false;
whiteBottom = false;
enemyWay = EnemyWay.LEFT;
right();
}
private void setInitLayout() {
setIcon(enemyR);
setSize(E_WIDTH, E_HEIGTH);
setLocation(x, y);
}
@Override
public void left() {
enemyWay = EnemyWay.LEFT;
left = true;
whiteBottom = false;
setIcon(enemyL);
// 메인 작업자는 계속 키 입력을 받아야함
new Thread(new Runnable() {
@Override
public void run() {
while (left) {
x -= SPEED;
setLocation(x, y);
if (whiteBottom) {
System.out.println("작동함");
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
right();
}
}).start();
}
@Override
public void right() {
enemyWay = EnemyWay.RIGHT;
right = true;
whiteBottom = false;
setIcon(enemyR);
new Thread(new Runnable() {
@Override
public void run() {
while (right) {
x += SPEED;
setLocation(x, y);
if(whiteBottom) {
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
left();
}
}).start();
}
@Override
public void up() {
System.out.println("점프");
up = true;
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 130 / JUMPSPEED; i++) {
y -= JUMPSPEED;
setLocation(x, y);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 객체의 상태값을 잘 조절해야 한다.
up = false;
down();
}
}).start();
}
@Override
public void down() {
System.out.println("다운");
down = true;
new Thread(new Runnable() {
@Override
public void run() {
while (down) {
y += SPEED;
setLocation(x, y);
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
down = false;
}
}).start();
}
}
package bubble.components;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import bubble.BubbleFrame;
import bubble.interfaces.Moveable;
import bubble.service.BackgroundBubbleService;
public class Bubble extends JLabel implements Moveable {
private Player player;
private BubbleFrame mContext;
private BackgroundBubbleService backgroundBubbleService;
private int x;
private int y;
// 움직임 상태
private boolean left;
private boolean right;
private boolean up;
// 적군을 맞춘 상태
private int state; // 0 : 기본 물방울, 1 : 적을 가둔 상태 물방울
private ImageIcon bubble; // 기본 물방울
private ImageIcon bubbled; // 적을 가둔 물방울
private ImageIcon bomb; // 물방울 팡!
// 연관관계, 의존성 컴포지션 관계, 생성자 의존 주입 (DI)
public Bubble(BubbleFrame mContext) {
this.mContext = mContext;
this.player = mContext.getPlayer();
initData();
setInitLayout();
}
// get, set
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Player getPlayer() {
return player;
}
public void setPlayer(Player player) {
this.player = player;
}
public boolean isLeft() {
return left;
}
public void setLeft(boolean left) {
this.left = left;
}
public boolean isRight() {
return right;
}
public void setRight(boolean right) {
this.right = right;
}
public boolean isUp() {
return up;
}
public void setUp(boolean up) {
this.up = up;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public ImageIcon getBubble() {
return bubble;
}
public void setBubble(ImageIcon bubble) {
this.bubble = bubble;
}
public ImageIcon getBubbled() {
return bubbled;
}
public void setBubbled(ImageIcon bubbled) {
this.bubbled = bubbled;
}
public ImageIcon getBomb() {
return bomb;
}
public void setBomb(ImageIcon bomb) {
this.bomb = bomb;
}
private void initData() {
bubble = new ImageIcon("img/bubble.png");
bubbled = new ImageIcon("img/bubbled.png");
bomb = new ImageIcon("img/bomb.png");
backgroundBubbleService = new BackgroundBubbleService(this);
left = false;
right = false;
up = false;
state = 0;
}
private void setInitLayout() {
x = player.getX();
y = player.getY();
setIcon(bubble);
setSize(50, 50);
setLocation(x, y);
}
@Override
public void left() {
left = true;
for (int i = 0; i < 400; i++) {
x--;
setLocation(x, y);
if (backgroundBubbleService.leftWall()) {
break;
}
// 현재 버블의 x, y 좌표 값을 알고 있다
System.out.println("적군 x 좌표 위치 : " + mContext.getEnemy().getX());
System.out.println("적군 y 좌표 위치 : " + mContext.getEnemy().getY());
// x 절대값만 확인해 보자.
int absX = Math.abs(x - mContext.getEnemy().getX());
System.out.println("absXResult : " + absX);
int absY = Math.abs(y - mContext.getEnemy().getY());
System.out.println("absYResult : " + absY);
if (absX < 40 && absY < 50) {
if (mContext.getEnemy().getState() == 0) {
crash();
}
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
left = false;
up();
}
@Override
public void right() {
right = true;
for (int i = 0; i < 400; i++) {
x++;
setLocation(x, y);
if (backgroundBubbleService.rightWall()) {
break;
}
int absX = Math.abs(x - mContext.getEnemy().getX());
int absY = Math.abs(y - mContext.getEnemy().getY());
if (absX < 40 && absY < 50) {
if (mContext.getEnemy().getState() == 0) {
crash();
}
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
right = false;
up();
}
@Override
public void up() {
up = true;
while (up) {
y--;
setLocation(x, y);
if (backgroundBubbleService.topWall()) {
break;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
up = false;
clearBubble();
}
private void clearBubble() {
try {
Thread.sleep(3000);
setIcon(bomb);
Thread.sleep(500);
// todo 테스트 필요 !!
setIcon(null);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void crash() {
// 적군이 살아 있는 상태에서
// 버블에 갇힌 상태로 변경
mContext.getEnemy().setState(1);
state = 1;
setIcon(bubbled);
// mContext.getEnemy().setIcon(null);
mContext.remove(mContext.getEnemy());
// mContext.getEnemy() 가바지 컬렉터의 제거 대상이 된다.
mContext.repaint();
}
}
package bubble.service;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import bubble.components.Enemy;
/**
* 현재 메인 쓰레드는 너~무 바쁨
* 백그라운드에서 계속 Player의 움직임을 관찰할 예정
*/
public class BackgroundEnemyService implements Runnable {
private BufferedImage image;
private Enemy enemy;
// 생성자 의존 주입 DI
public BackgroundEnemyService(Enemy enemy) {
this.enemy = enemy;
try {
image = ImageIO.read(new File("img/backgroundMapService.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while(true) {
int bottomColorLeft = image.getRGB(enemy.getX() + 20, enemy.getY() + 50 + 5);
int bottomColorRight = image.getRGB(enemy.getX() + 50 + 10, enemy.getY() + 50 + 5);
// 흰색이면 -----> int 값이 - 2
if(bottomColorLeft == -1 || bottomColorRight == -1) {
enemy.setWhiteBottom(true);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
정리
1. 적군 클래스 설계
- 플레이어 클래스 복붙해서 어택만 지운다
2. 태어나자 마자 움직이게 함
- 생성자에서 쓰레드를 호출함 (디폴트를 right()로 설정)
3. 적군이 버블에 맞으면 버블에 갇힘
- 좌표 차이의 절대값을 이용해서 이미지가 닿았을때 bubbled 이미지로 변경
4. 바닥에서만 움직이도록 자연스럽게
- 기존에 작성된 플레이어 서비스 클래스를 참고해 흰색 바닥일때 불리언 값을 바꿈
- 움직일 때마다 불리언 값을 읽어서 흰색 바닥인지 확인하고 흰색 바닥일 경우 방향을 바꿈
'Java > Swing 프로젝트' 카테고리의 다른 글
Swing 프로젝트 (0) | 2024.05.07 |
---|---|
Bubble 버블 지우기 - 9 (0) | 2024.05.07 |
Bubble 버블 생성 동작 수정 - 8 (0) | 2024.05.07 |
Bubble 버블 벽 감지 - 7 (0) | 2024.05.07 |
Bubble 버블 동작 처리 - 6 (1) | 2024.05.03 |