Bubble 적군 생성 - 10

목표

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. 바닥에서만 움직이도록 자연스럽게

  • 기존에 작성된 플레이어 서비스 클래스를 참고해 흰색 바닥일때 불리언 값을 바꿈
  • 움직일 때마다 불리언 값을 읽어서 흰색 바닥인지 확인하고 흰색 바닥일 경우 방향을 바꿈

 

Swing 목차로 돌아가기

 

'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