YeaLow
article thumbnail
Published 2022. 10. 11. 01:42
BubbleBubble-final Java

길고 길었던 Bubble Bubble 프로젝트가 끝이 났다. 사실 완벽하게 끝난건 아니다  

Bubble쪽 List로 받은 내용도 삭제해야 하는데.. 일단 마무리된거만 올릴려고 한다. 

필기는 이때까지 한거 다 적어뒀으니 참고 하실분들은 참고 하세요.

 

BubbleFrame.java

package bubble.test.ex18;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BubbleFrame extends JFrame {

	private BubbleFrame mContext = this;
	private JLabel backgroundMap;
	private Enemy enemy;
	private Player player;

	public BubbleFrame() { // 생성자 만들기
		initObject();
		initSetting();
		initListener(); // listener 추가
		setVisible(true);
	}

	private void initObject() {
		backgroundMap = new JLabel(new ImageIcon("image/backgroundMap.png")); // label 안에 이미지 넣음
		setContentPane(backgroundMap);
//		backgroundMap.setSize(100,100);
//		backgroundMap.setLocation(300,300);
//		backgroundMap.setSize(1000,600);
//		add(backgroundMap);// JFrame에 JLabel이 그려진다.

		player = new Player(mContext); // Player함수를 호출하여 BubbleFrame에 추가한다
		add(player);
		
		enemy = new Enemy(mContext);
		add(enemy);
		new BGM();
	}

	private void initSetting() {
		setSize(1000, 640);
		setLayout(null);// absolute 레이아웃 (자유롭게 그림을 그릴 수 있다.)
		setLocationRelativeTo(null); // JFrame 가운데 배치하기
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // x버튼으로 창을 끌 때 JVM 같이 종료 하기
	}

	private void initListener() { // this 이친구의 this
		addKeyListener(new KeyAdapter() { // 람다식으로 Interface를 가져올시 전부 기능을 정의 해야함 하지만 Adapter를 사용해서 정의가 가능하다
			// 키보드 클릭 이벤트 핸들러
			@Override
			public void keyPressed(KeyEvent e) {
//				System.out.println(e.getKeyCode()); //  실행하여 방향키를 입력해본다
				// 39 오른쪽
				// 37 왼쪽 숫자로 표현하면 알아보기 힘들다 KeyEvent.VK_ 를 활용하여 알기 쉽게 한다
				// 40 밑
				// 38 위

				switch (e.getKeyCode()) {
				case KeyEvent.VK_LEFT:
					if (!player.isLeft() && !player.isLeftWallCrash()) {
						player.left();
					}
					break;
				case KeyEvent.VK_RIGHT:
					if (!player.isRight() && !player.isRightWallCrash()) {
						player.right();
					}
					break;
				case KeyEvent.VK_UP:
					if (!player.isUp() && !player.isDown()) {
						player.up();
					}
					break;
				case KeyEvent.VK_SPACE: //버블의 주체는 player인데 bubbleFrame에서 지금 new를 하고 있다.
//					System.out.println("발싸!");
//					Bubble bubble = new Bubble(mContext); // this 익명 클래스의 정보
//					add(bubble);
					player.attack();
					break;
					}
			}
//				case KeyEvent.VK_DOWN: 떨어지거나 할때 사용하는데 따로 down키를 눌릴 일이 없다
//					player.down(); 
//					break;
			

			// 키보드 해제 이벤트 핸들러
			@Override
			public void keyReleased(KeyEvent e) {
				switch (e.getKeyCode()) {
				case KeyEvent.VK_LEFT:
					player.setLeft(false);
					break;
				case KeyEvent.VK_RIGHT:
					player.setRight(false);
					break;
				}
			}

		});
	}

	public static void main(String[] args) {
		new BubbleFrame();

	}
}

Moveable.java

package bubble.test.ex18;

public interface Moveable {
	public abstract void left();
	public abstract void right();
	public abstract void up();
	default public void down() {}; 
	default public void attack() {};
	// public이 아닌이유 버블은 공격의 주체가 아니다 -> 공격은 player가 하는것
	// 자바 높은 버전부터 나온 문법
	// default를 사용하면 인터페이스도 몸체가 있는 메서드를 만들수 있다. (다중 상속이 안되는 것이 많기 때문에)
	// 그래서 어댑터 패턴보다는 default를 사용하는것이 좋다 .
}

Player.java

package bubble.test.ex18;

import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

// class player -> new 가능한 애들!! 게임에 존재할 수 있음. (추상메서드를 가질 수 없다.)
@Setter
@Getter
public class Player extends JLabel implements Moveable { // player 자체가 label이다

	private BubbleFrame mContext; // 못받아 오니BubbleFrame 호출해야한다
	private List<Bubble> bubbleList;
	// 위치 상태
	private int x;
	private int y;

	// 플레이어의 방향
	private PlayerWay playerWay;

	// 움직임 상태
	private boolean left;
	private boolean right;
	private boolean up;
	private boolean down;

	// 벽에 충돌한 상태
	private boolean leftWallCrash;
	private boolean rightWallCrash;

	// 플레이어 속도 상태
	private final int SPEED = 4; // 상수처리
	private final int JUMP = 2; // up, down

	private ImageIcon playerR, playerL;

	public Player(BubbleFrame mContext) {
		this.mContext = mContext;
		initObject(); // 오브젝트 세팅
		initSetting();
		initBackgroundPlayerService();
	}

	private void initObject() {
		playerR = new ImageIcon("image/playerR.png"); // 이미지 ImageIcon에 사진 추가
		playerL = new ImageIcon("image/playerL.png");
		bubbleList = new ArrayList<>();
	}

	private void initSetting() { // 기본 시작 위치
		x = 80;
		y = 535;

		// 최초 상태 -> 움직인다 (좌표가 이동한다)
		// 키보드 오른쪽을 누른다 -> 오른쪽으로 간다
		left = false;
		right = false;
		up = false;
		down = false;

		leftWallCrash = false;
		rightWallCrash = false;

		playerWay = PlayerWay.RIGHT;
		setIcon(playerR);
		setSize(50, 50);
		setLocation(x, y);
	}

	private void initBackgroundPlayerService() {// Thread 사용시 Runable 사용해야하지만 BackgroundPlayerService자체가 Runable 상속 받았기
												// 때문에 바로 가능
		new Thread(new BackgroundPlayerService(this)).start();
	}

	@Override
	public void attack() { // Moveable에서 attack을 호출한다.
		new Thread(() -> { // 어택 호출시 쓰레드 실행한다.
			Bubble bubble = new Bubble(mContext); // Thread가 시작되면서 bubble이 만들어 지고 왼쪽 아니면 오른쪽으로만 이동하면 된다
			mContext.add(bubble);
			bubbleList.add(bubble);
			if (playerWay == playerWay.LEFT) {
				bubble.left();
			} else {
				bubble.right();
			}
		}).start();
	}

	// 이벤트 핸들러
	@Override
	public void left() {
		playerWay = PlayerWay.LEFT;
		left = true;
		new Thread(() -> { // Thread 생성
			while (left) {
				x = x - SPEED; // x축 1만큼 - 이동
				setIcon(playerL); // 왼쪽으로 갈때는 왼쪽 이미지
				setLocation(x, y);
				try {
					Thread.sleep(10);// 0.01초
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start(); // Thread에는 Runable의 익명 클래스가 필요하다
	}

	@Override
	public void right() {
		playerWay = PlayerWay.RIGHT;
		right = true;
		new Thread(() -> {
			while (right) {
				setIcon(playerR); // 왼쪽으로 갈때는 오른쪽 이미지
				x = x + SPEED; // x축 1만큼 +이동
				setLocation(x, y);
				try {
					Thread.sleep(10);// 0.01초
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start(); // Thread에는 Runable의 익명 클래스가 필요하다

	}

	// left + up , right + up 가능하다 Thread가 없으면 불가능 함
	@Override
	public void up() {
		System.out.println("짬푸");
		up = true;
		new Thread(() -> {
			for (int i = 0; i < 130 / JUMP; i++) { // JUMP 변경시에도 알아보기 좋다. 나중에 복잡해진다
				y = y - JUMP; // y값을 - 하는게 점프
				setLocation(x, y);
				try {
					Thread.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			up = false;
			down();
		}).start();
	}

	@Override
	public void down() {
//		System.out.println("down");
		down = true;
		new Thread(() -> {
			while (down) { // JUMP 변경시에도 알아보기 좋다. 나중에 복잡해진다
							// for문 쓰면 부조건 바닥에 떨어짐 while문 변경 -> 떨어지다가 false로 바뀌면서 멈춤
				y = y + JUMP; // y값을 - 하는게 점프
				setLocation(x, y);
				try {
					Thread.sleep(3);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			down = false;
		}).start();
	}
	

}

PlayerWay.java(Enum)

package bubble.test.ex18;

public enum PlayerWay {
	LEFT,RIGHT;
}

BackgroundPlayerService.java

package bubble.test.ex18;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;

import javax.imageio.ImageIO;

// 메인 쓰레드 바쁨 - 키보드 이벤트를 처리하기 바쁨.
// Background에서 플레이어의 움직임을 관찰하는 Class
public class BackgroundPlayerService implements Runnable {

	private BufferedImage image; // image를 Buffered로 읽어야 test 가능
	private Player player;
	private List<Bubble> bubbleList; // 전체 리스트를 가져와서 계산을 한다.
	// 플레이어, 버블

	public BackgroundPlayerService(Player player) {
		this.player = player;
		this.bubbleList = player.getBubbleList();
		try {
			image = ImageIO.read(new File("image/backgroundMapService.png"));
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}

	@Override
	public void run() {
		while (true) {

			// 1. 버블 충돌 체크
			for (int i = 0; i < bubbleList.size(); i++) {
				Bubble bubble = bubbleList.get(i);
				if (bubble.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();
						break;
					}
				}
			}

			// 2. 벽 충돌 체크
			// 색상 확인 -> 부딪치는곳 영역 잡기 위해서 사용중
			Color leftColor = new Color(image.getRGB(player.getX() - 10, player.getY() + 25));
			Color rightColor = new Color(image.getRGB(player.getX() + 50 + 15, player.getY() + 25));
			// -2가 나온다는 뜻은 바닥에 색깔이 없이 흰색
			int bottomColor = image.getRGB(player.getX() + 10, player.getY() + 50 + 5) // 가장 왼쪽 하단 = -1
					+ image.getRGB(player.getX() + 40, player.getY() + 50 + 5); // 가장 오른쪽 하단 = -1
//			System.out.println("bottomColor" + bottomColor);
//			System.out.println("leftColor : " + leftColor);
//			System.out.println("rightColor : " + rightColor);
//			Color color = new Color(image.getRGB(player.getX(), player.getY()));
//			System.out.println("색상 : " + color);	

			// 바닥 충돌 확인
			if (bottomColor != -2) {
//				System.out.println("바닥에 충돌함");
				player.setDown(false);
			} else { // -2 일때 실행됨 => 내 바닥 색깔이 하얀색이라는 것
				if (!player.isUp() && !player.isDown()) { // player가 isUP + is Down 상태가 아닐때
					player.down();
				}

			}

			// 외벽 충돌 확인
			if (leftColor.getRed() == 255 && leftColor.getGreen() == 0 && leftColor.getBlue() == 0) { // RGB 빨간색
//				System.out.println("왼쪽 벽에 충돌함");
				player.setLeftWallCrash(true);
				player.setLeft(false);
			} else if (rightColor.getRed() == 255 && rightColor.getGreen() == 0 && rightColor.getBlue() == 0) {
//				System.out.println("오른쪽 벽에 충돌함");
				player.setRightWallCrash(true);
				player.setRight(false);// 이것만 하면 되는줄 알았지만 계속 누르게 되면 뜷고 들어가게 된다.
			} else {
				player.setLeftWallCrash(false);
				player.setRightWallCrash(false);
			}
			try { // sleep 없으면 너무 빨리 실행된다.
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

}

Bubble.Java

package bubble.test.ex18;


import javax.swing.ImageIcon;
import javax.swing.JLabel;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class Bubble extends JLabel implements Moveable {

	// 의존성 콤포지션 -> bubble은 player에 의존적이다
	private BubbleFrame mContext;
	private Player player;
	private Enemy enemy; // 적군이 여러명이면 Enemy 컬렉션으로 만들면 된다.
	private BackgroundbubblerService backgroundbubblerService; // bubble이 만들어질때마다 new

	// 위치 상태
	private int x;
	private int y;

	// 움직임 상태
	private boolean left;
	private boolean right;
	private boolean up;
//	private boolean down;  방울은 밑으로 못간다

	// 적군을 맞춘 상태
	private int state; // 0(물방울), 1(적을 가둔 물방울)

	private ImageIcon bubble; // 물방울
	private ImageIcon bubbled; // 적을 가둔 물방울
	private ImageIcon bomb; // 물방울이 터진 상태

	public Bubble(BubbleFrame mContext) { // player를 넣어줘야 방울의 위치를 잡아 줄수 있다
		this.mContext = mContext; // 모든정보를 가진 Context가 있으니까 플레이어 정보를 들고 올수 있다.
		this.player = mContext.getPlayer();
		this.enemy = mContext.getEnemy();
		initObject();
		initSetting();
//		initThread();
	}

	private void initSetting() {
		left = false;
		right = false;
		up = false;

		x = player.getX();
		y = player.getY();
		// bubble의 방향이 결정되어야 한다.
		setIcon(bubble);
		setSize(50, 50);
		state = 0;
	}

	private void initObject() {
		bubbled = new ImageIcon("image/bubbled.png");
		bubble = new ImageIcon("image/bubble.png");
		bomb = new ImageIcon("image/bomb.png");
		backgroundbubblerService = new BackgroundbubblerService(this);

	}

//	private void initThread() {
//		// 버블은 쓰레드가 하나만 필요하다.
//		new Thread(()->{
//			if(player.getPlayerWay() == PlayerWay.LEFT) {
//				left();
//			} else {
//				right();
//			}
//		}).start();
//	}
	@Override
	public void left() {
		left = true;
		for (int i = 0; i < 400; i++) {
			x--;
			setLocation(x, y);

			if (backgroundbubblerService.leftWall()) {
				left = false;
				break;
			}

			// 40과 60의 범위 절대값
			if ((Math.abs(x - enemy.getX()) < 10)
					&& (Math.abs(y - enemy.getY()) > 0 && Math.abs(y - enemy.getY()) < 50)) {
				System.out.println("물방울이 적군과 충돌하였습니다.");
				if (enemy.getState() == 0) {
					attack();
					break;
				}
			}

			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		up();
	}

	@Override
	public void right() {
		right = true;
		for (int i = 0; i < 400; i++) {
			x++;
			setLocation(x, y);

			if (backgroundbubblerService.rightWall()) {
				right = false;
				break;
			}

			// 아군과 적군의 거리가 10의 차이가 나면
			if ((Math.abs(x - enemy.getX()) < 10)
					&& (Math.abs(y - enemy.getY()) > 0 && Math.abs(y - enemy.getY()) < 50)) {
				System.out.println("물방울이 적군과 충돌하였습니다.");
				if (enemy.getState() == 0) {
					attack();
					break;
				}
			}

			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		up();
	}

	@Override
	public void up() {
		up = true;
		while (up) {
			y--;
			setLocation(x, y);

			if (backgroundbubblerService.topWall()) {
				up = false;
				break; // break 필요는 없지만 이단계에서 바로 체크가 되어서 2번 안돌아도 되니까 break 사용함
			}

			try {
				if (state == 0) { // 기본 물방울
					Thread.sleep(1);

				} else { // 적은 가둔 물방울
					Thread.sleep(10);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if (state == 0)
			clearBubble(); // 천장에 버블이 도착하고 나서 3초 후에 메모리에서 소멸
	}

	@Override
	public void attack() {
		state = 1;
		enemy.setState(1);
		setIcon(bubbled);
		mContext.remove(enemy); // 메모리에서 사라지게 한다. (가비지 컬렉션 -> 즉시 발동하지 않음)
		mContext.repaint(); // 깔끔하게 안사라져서 리페인트 작업 해야한다. 화면갱신
	}

	// 행위 -> clear (동사) -> bubble (목적어)
	private void clearBubble() {// 다른곳에서 호출할일이 없기 때문에 private 사용
		try {
			Thread.sleep(3000);
			setIcon(bomb);
			Thread.sleep(500);
			mContext.remove(this); // bubbleFrame 의 bubble이 메모리에서 소멸된다.
			mContext.repaint(); // bubbleFrame 의 전체를 다시 그린다.(메모리에서 없는 건 안그린다.)

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	public void clearBubbled() {
		new Thread(()->{
			System.out.println("clearBubbled");
			try {
				up = false;
				setIcon(bomb);
				Thread.sleep(1000);
				mContext.remove(this);
				mContext.repaint();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}).start();
	
	}
}

BackgroundbubblerService.java

package bubble.test.ex18;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;

public class BackgroundbubblerService {// bubble이 만들어질때마다 유지 되어야한다. -> 버블은 언제 만들어지나?(만들어지는 시점) -> VK_SPACE에서

	private BufferedImage image;
	private Bubble bubble;

	public BackgroundbubblerService(Bubble bubble) {
		this.bubble = bubble;
		try {
			image = ImageIO.read(new File("image/backgroundMapService.png"));
		} catch (Exception e) {

		}
	}

	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) {
			return true;
		}
		return false;
	}

	public boolean rightWall() {
		Color rightColor = new Color(image.getRGB(bubble.getX() + 50 + 15, bubble.getY() + 25));
		if (rightColor.getRed() == 255 && rightColor.getGreen() == 0 && rightColor.getBlue() == 0) {
			return true;
		}
		return false;
	}

	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) {
			return true;
		}
		
		return false;
	}
}

 

Enemy.Java

package bubble.test.ex18;

import javax.swing.ImageIcon;
import javax.swing.JLabel;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

// class player -> new 가능한 애들!! 게임에 존재할 수 있음. (추상메서드를 가질 수 없다.)
@Getter
@Setter
public class Enemy extends JLabel implements Moveable { // player 자체가 label이다

	private BubbleFrame mContext; // 못받아 오니BubbleFrame 호출해야한다
	// 위치 상태
	private int x;
	private int y;

	// 적군의의 방향
	private EnemyWay enemyWay;

	// 움직임 상태
	private boolean left;
	private boolean right;
	private boolean up;
	private boolean down;

	private int state; // 0(살아있는 상태), 1(물방울에 갇힌 상태)
	
	// 적군의 속도 상태
	private final int SPEED = 3; // 상수처리
	private final int JUMP = 1; // up, down

	private ImageIcon enemyR, enemyL;

	public Enemy(BubbleFrame mContext) {
		this.mContext = mContext;
		initObject(); // 오브젝트 세팅
		initSetting();
		initBackgroundEnemyService();
		right();
	}

	private void initObject() {
		enemyR = new ImageIcon("image/enemyR.png"); // 이미지 ImageIcon에 사진 추가
		enemyL = new ImageIcon("image/enemyL.png");
	}

	private void initSetting() { // 기본 시작 위치
		x = 480;
		y = 178;

		// 최초 상태 -> 움직인다 (좌표가 이동한다)
		// 키보드 오른쪽을 누른다 -> 오른쪽으로 간다
		left = false;
		right = false;
		up = false;
		down = false;
	
		state = 0;

		enemyWay = enemyWay.RIGHT;
		setIcon(enemyR);
		setSize(50, 50);
		setLocation(x, y);
	}

	private void initBackgroundEnemyService() {// Thread 사용시 Runable 사용해야하지만 BackgroundPlayerService자체가 Runable 상속 받았기
												// 때문에 바로 가능
		new Thread(new BackgroundEnemyService(this)).start();
	}

	// 이벤트 핸들러
	@Override
	public void left() {
		enemyWay = EnemyWay.LEFT;
		left = true;
		new Thread(() -> { // Thread 생성
			while (left) {
				x = x - SPEED; // x축 1만큼 - 이동
				setIcon(enemyL); // 왼쪽으로 갈때는 왼쪽 이미지
				setLocation(x, y);
				try {
					Thread.sleep(10);// 0.01초
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start(); // Thread에는 Runable의 익명 클래스가 필요하다
	}

	@Override
	public void right() {
		enemyWay = EnemyWay.RIGHT;
		right = true;
		new Thread(() -> {
			while (right) {
				setIcon(enemyR); // 왼쪽으로 갈때는 오른쪽 이미지
				x = x + SPEED; // x축 1만큼 +이동
				setLocation(x, y);
				try {
					Thread.sleep(10);// 0.01초
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start(); // Thread에는 Runable의 익명 클래스가 필요하다

	}

	@Override
	public void up() {
		up = true;
		new Thread(() -> {
			for (int i = 0; i < 130 / JUMP; i++) { // JUMP 변경시에도 알아보기 좋다. 나중에 복잡해진다
				y = y - JUMP; // y값을 - 하는게 점프
				setLocation(x, y);
				try {
					Thread.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			up = false;
			down();
		}).start();
	}

	@Override
	public void down() {
//		System.out.println("down");
		down = true;
		new Thread(() -> {
			while (down) { // JUMP 변경시에도 알아보기 좋다. 나중에 복잡해진다
							// for문 쓰면 부조건 바닥에 떨어짐 while문 변경 -> 떨어지다가 false로 바뀌면서 멈춤
				y = y + JUMP; // y값을 - 하는게 점프
				setLocation(x, y);
				try {
					Thread.sleep(3);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			down = false;
		}).start();
	}

}

EnemyWay.java(Enum)

package bubble.test.ex18;

public enum EnemyWay {
	LEFT,RIGHT;
}

BackgroundEnemyService.java

package bubble.test.ex18;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.List;

import javax.imageio.ImageIO;

// 메인 쓰레드 바쁨 - 키보드 이벤트를 처리하기 바쁨.
// Background에서 플레이어의 움직임을 관찰하는 Class
public class BackgroundEnemyService implements Runnable {

	private BufferedImage image; // image를 Buffered로 읽어야 test 가능
	private Enemy enemy;
	// 플레이어, 버블
	public BackgroundEnemyService(Enemy enemy) {
		this.enemy = enemy;
		try {
			image = ImageIO.read(new File("image/backgroundMapService.png"));
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}

	@Override
	public void run() {
		while (enemy.getState() == 0) {
			Color leftColor = new Color(image.getRGB(enemy.getX() - 10, enemy.getY() + 25));
			Color rightColor = new Color(image.getRGB(enemy.getX() + 50 + 15, enemy.getY() + 25));
			int bottomColor = image.getRGB(enemy.getX() + 10, enemy.getY() + 50 + 5) // 가장 왼쪽 하단 = -1
					+ image.getRGB(enemy.getX() + 40, enemy.getY() + 50 + 5); // 가장 오른쪽 하단 = -1
			if (bottomColor != -2) {
//				System.out.println("바닥에 충돌함");
				enemy.setDown(false);
			} else { // -2 일때 실행됨 => 내 바닥 색깔이 하얀색이라는 것
				if (!enemy.isUp() && !enemy.isDown()) { // player가 isUP + is Down 상태가 아닐때
					enemy.down();
				}

			}

			// 외벽 충돌 확인
			if (leftColor.getRed() == 255 && leftColor.getGreen() == 0 && leftColor.getBlue() == 0) { // RGB 빨간색
				enemy.setLeft(false);
				if(!enemy.isRight()) {
					enemy.right();
				}
			} else if (rightColor.getRed() == 255 && rightColor.getGreen() == 0 && rightColor.getBlue() == 0) {
				enemy.setRight(false);// 이것만 하면 되는줄 알았지만 계속 누르게 되면 뜷고 들어가게 된다.
				if(!enemy.isLeft()) {
					enemy.left();
				}
			}
			try { // sleep 없으면 너무 빨리 실행된다.
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

}

 

BGM.java

package bubble.test.ex18;

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.UnsupportedAudioFileException;

public class BGM {
	public BGM() {
			try {
				AudioInputStream ais = AudioSystem.getAudioInputStream(new File("sound/bgm.wav"));
				Clip clip = AudioSystem.getClip();
				clip.open(ais);
				// 소리 설정
				FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
				
				// 볼륨 조정
				gainControl.setValue(-30.0f);
				
				clip.start();
			} catch (Exception e) {
				e.printStackTrace();
			}
	}
}

환호의 빠뽀먼스 완성!!

힘들었습니다. 난중에 보강해서 다시 올리겠습니다 쓩!

profile

YeaLow

@YeaLow

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!