본문 바로가기

Coding_Study/Java_Code_Memo

JButton으로 슈팅게임 2-3 몬스터 1 만들기

이번에는 하늘에서 떨어지는 몬스터를 만들어볼 생각입니다.

당연히 몬스터도 JButton이겠죠?

 

저는 몬스터1의 이미지를 붉은 별로 했어요.

배경이 너무 마음에 드는데 적은 노란별로 했더니 안보이더라고요.

고민하는 저한테 친구가 별이 꼭 노란색이어야 해? 라고 물어봤어요.

그래서 바로 색을 변경, 훨씬 눈에도 잘 들어오고 낙엽같아서 감성이 묻어나네요.

(고마워 칭구야 :> )

 

게임의 스토리(?)에 따르면, 주인공은 첫 패널에 나온 여자의 부탁으로 악당에게 있는 달을 찾으러 갑니다.

그리고 저 별은 악당의 부하인 거죠.

자, 해봅시다.

 

전제 : 몬스터1 JButton class에 Runnable로 Thread 구현

          'Play_Phase1'에 Thread를 추가해 몬스터 객체 자동 소환

 

오늘 할 일 : 'Play_Phase1' class에 Runnable 추가

                  몬스터1 JButton class를 일정 시간마다 소환

                  (추가) 총알의 속도를 조절하기 위하여 같은 Thread 이용하기

 

 

 

 

 

- Monster1 class에 JButton 상속받고 Runnable로 Thread추가

- 좌표 x의 값은 랜덤으로 설정 _ Math.random사용_ 양 옆에 20정도의 여유를 둠

- 좌표 y의 값은 -50으로 화면 밖에서 생성하여 자연스럽게 나타나게 조정

- run()에 while문을 사용하여 y좌표 700이 되면 끝나고 JButton이 사라지게 함

   //while문은 꼭 써야할 이유가 아니라면 실수했을 때 컴퓨터에 무리가게 한다고 자제하라고 주워들었는데 맞나요 ..?

   //그렇지만 여기에서는 while문이 편하게 느껴지더라고요.

   // 혹시 더 나은 조건이 있다면 조언 부탁드립니다.

package Game1;

import javax.swing.ImageIcon;
import javax.swing.JButton;

public class Monster1 extends JButton implements Runnable {
	Play_Phase1 play1;
	
	private int monX, monY;
	
	Monster1(Play_Phase1 play1){
		this.play1 = play1;
		
		monX =(int)((Math.random()*420)+20); //위치 설정
		monY = -50;
		
		ImageIcon icmon = new ImageIcon("별_빨강.png"); //이미지 설정
		this.setIcon(icmon);
		this.setBorderPainted(false);
		this.setFocusPainted(false);
		this.setContentAreaFilled(false);
		this.setBounds(monX, monY, 50, 50);
		
		/**add Monster*/
		play1.add(this);
	}

	
	@Override
	public void run() {
		while(monY<700){
			try {
				Thread.sleep(100);//적이 떨어지는 시간
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			/**set Location*/
			this.setLocation(monX, monY+=15);
			
		}
		play1.remove(this);
		play1.repaint();
		play1.revalidate();
	}

}

 

 

- 플레이 메인(Play_Phase1)에 Runnable을 추가

- run()안에 int타입의 countTime변수를 추가하여 지나간 시간만큼 그 수를 더하게 함

- Monster1은 1.5초에 하나씩 나오게 설정

- Thread 작업하는김에 총알이 화면에 출력되는 갯수를 줄이기 위해 시간 제한(0.5초)을 둠

  조건을 (SpaceBar를 누른다) + (0.5초) 두개를 병합해서 줌

  //countTime%500 == 0&& isFire == true

- boolean타입의 isFire를 추가하여 Space Bar를 눌렀을 때 true로 바뀌게 설정

@Override
	public void keyPressed(KeyEvent e) {
		if(e.getKeyCode()==KeyEvent.VK_RIGHT) {
			meX += 20;
		} else if(e.getKeyCode()==KeyEvent.VK_LEFT) {
			meX -= 20;
		} else if(e.getKeyCode()==KeyEvent.VK_UP) {
			meY -= 20;
		} else if(e.getKeyCode()==KeyEvent.VK_DOWN) {
			meY += 20;
		} else if(e.getKeyCode()==KeyEvent.VK_SPACE) {
			 if(!isSpacePress){ //스페이스 연사를 방지하기 위함
				isSpacePress=true;
			}
			 isFire =true;
		}
		if(meX < 10) {  //일정 범위 이상 못 나가도록
			meX = 10;
		} else if(meX > 450) {
			meX = 440;
		} else if(meY < 300) {
			meY = 300;
		} else if(meY > 700) {
			meY = 700;
		}
		
		btnMe.setLocation(meX, meY); //위치 설정
		setMePosition(meX, meY); //총알을 위한 위치 설정 메소드
		
		this.repaint(); //화면 갱신
		this.revalidate();
	}
@Override
	public void run() {
		while(true) {
			try {
				Thread.sleep(500);//객체가 생성되는 시간
				countTime += 500;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			/**Monster 1 count*/
			if(countTime%1500 == 0) {
				monster1 = new Monster1(this);
				(new Thread(monster1)).start();
			}
			
			/**Bullet count*/
			if(countTime%500 == 0&& isFire == true) {
				isFire = false;
				bullet = new BtnBullet(this);
				(new Thread(bullet)).start();
			}
		}
		
	}

 

자, 여기서 문제.

총알과 몬스터의 Thread는 플레이 패널(Play_Phase1)에서 실행시켜줬는데,

'Play_Phase1'의 run()은 어디서 실행시켜야 할까요?

 

여기서 시행착오를 좀 겪었습니다. 패널 내에서,

Thread t1 = new Thread(this);
t1.start();

이렇게 했는데 시작을 안 하더라고요.

 

혹시 저번 focus문제 기억하시나요?

2020/12/11 - [Java_Study/Code_Memo] - JButton으로 슈팅게임 2-1 주인공 만들기

 

JButton으로 슈팅게임 2-1 주인공 만들기

저는 게임 구상을 페이즈 1,2(Phase1, Phase2)로 나눠서 진행하도록 했습니다. Phase1 에서는 일반 몹들이 나오고, 그 중 특정 몹(Monster)을 몇 번 이상 잡으면 Phase1이 종료, 보스(Boss)가 나오는 Phase2로 넘

mintpearl-story.tistory.com

여기서 Key Listener를 실행하기 위해 JFrame까지 갔었잖아요?

이번에도 같은 방법으로 해결했습니다.

 

- 메인 프레임(Main_StartHere)에 있는 JPanel연결 Method에서

  (new Thread(playPhase1)).start(); 를 실행시킨다! 

public void MainPnl2ToNext(int i) { //메인 패널에서 첫화면/게임화면 이동
		this.remove(main2);
		if (i == 1) { //첫 화면으로
			this.add(firstPage); 
		} else if (i ==2) { //게임 화면으로
			playPhase1 = new Play_Phase1(this);
			this.add(playPhase1); 
			playPhase1.setFocusable(true);
			playPhase1.requestFocus();
			(new Thread(playPhase1)).start();
		}
		this.repaint();
		this.revalidate();
	}

 

다음번에는 몬스터를 추가로 만들어볼 거예요.

이미 만들어놓은 몬스터가 있으니까 이번에는 좀 더 쉽겠죠? 제발 ;<