더보기

쿠키런 프로젝트 시리즈
1.준비
https://ondolroom.tistory.com/297
2.전역공간
https://ondolroom.tistory.com/298
3.JPanel생성자
https://ondolroom.tistory.com/299
4.mapMove메서드
https://ondolroom.tistory.com/300
5.hit메서드
https://ondolroom.tistory.com/301
6.fall메서드
https://ondolroom.tistory.com/302
7.jump메서드
https://ondolroom.tistory.com/303
8.paintComponent 및 결과
https://ondolroom.tistory.com/304

 

https://ondolroom.tistory.com/299

 

자바 스윙 쿠키런 만들기 MyPanel 생성자 수정 (프로젝트 진행)

https://ondolroom.tistory.com/298 자바 스윙 쿠키런 만들기 전역 변수 선언하기 (프로젝트 진행) 들어가기 전에... 아래 내용을 숙지하고 시작하자 https://ondolroom.tistory.com/279 자바 WindowBuilder 설치..

ondolroom.tistory.com

 

패널 생성자에서 필요한 메서드들 중 맵 발판 젤리 장애물 이동 및 작동을  아래에서 구현하고자 한다.

 

더보기로 전체코드 확인

더보기
void mapMove() {
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				while (true) {
					
					if(runPage > 800) { // 800픽셀 이동 마다 체력이 10씩 감소한다 (추후 맵길이에 맟추어 감소량 조절)
						c1.setHealth(c1.getHealth()-10);
						runPage = 0;
					}
					
					runPage +=gameSpeed; // 화면이 이동하면 runPage에 이동한 만큼 저장된다.
					
					
					if (b11.getX() < -(b11.getWidth()-1)) { // 배경1-1 이 -(배경넓이)보다 작으면, 즉 화면밖으로 모두나가면 배경 1-2뒤에 붙음
						b11.setX(b11.getWidth());
					}
					if (b12.getX() < -(b12.getWidth()-1)) { // 배경1-2 가 -(배경넓이)보다 작으면, 즉 화면밖으로 모두나가면 배경 1-1뒤에 붙음
						b12.setX(b12.getWidth());
					}
					
					
					// 배경의 x좌표를 -1 해준다 (왼쪽으로 흐르는 효과)
					b11.setX(b11.getX()-gameSpeed/3); 
					b12.setX(b12.getX()-gameSpeed/3);
					
					
					// 발판위치를 -4 씩 해준다. (왼쪽으로 흐르는 효과)
					for (int i = 0; i < fieldList.size(); i++) {
						
						Field tempField = fieldList.get(i); // 임시 변수에 리스트 안에 있는 개별 발판을 불러오자
						
						if(tempField.getX() < -90) { // 발판의  x좌표가 -90 미만이면 해당 발판을 제거한다.(최적화)
							
							fieldList.remove(tempField);
							
						} else {
							
							tempField.setX(tempField.getX() - gameSpeed);  // 위 조건에 해당이 안되면 x좌표를 줄이자
							
						}
					}
					
					// 젤리위치를 -4 씩 해준다.
					for (int i = 0; i < jellyList.size(); i++) {
						
						Jelly tempJelly = jellyList.get(i); // 임시 변수에 리스트 안에 있는 개별 젤리를 불러오자
						
						if(tempJelly.getX() < -90) { // 젤리의 x 좌표가 -90 미만이면 해당 젤리를 제거한다.(최적화)
							
							fieldList.remove(tempJelly);
							
						} else {
							
							tempJelly.setX(tempJelly.getX() - gameSpeed); // 위 조건에 해당이 안되면 x좌표를 줄이자
							
							foot = c1.getY() + c1.getHeight(); // 캐릭터 발 위치 재스캔
							
							if( // 캐릭터의 범위 안에 젤리가 있으면 아이템을 먹는다.
								c1.getImage() != slideIc.getImage()
								&& tempJelly.getX() + tempJelly.getWidth()*20/100 >= c1.getX()
								&& tempJelly.getX() + tempJelly.getWidth()*80/100 <= face
								&& tempJelly.getY() + tempJelly.getWidth()*20/100 >= c1.getY()
								&& tempJelly.getY() + tempJelly.getWidth()*80/100 <= foot
								&& tempJelly.getImage() != jellyEffectIc.getImage()) {
								
								tempJelly.setImage(jellyEffectIc.getImage()); // 젤리의 이미지를 이펙트로 바꾼다
								resultScore = resultScore + tempJelly.getScore(); // 총점수에 젤리 점수를 더한다
								
								
							} else if( // 슬라이딩 하는 캐릭터의 범위 안에 젤리가 있으면 아이템을 먹는다.
								c1.getImage() == slideIc.getImage()
								&& tempJelly.getX() + tempJelly.getWidth()*20/100 >= c1.getX()
								&& tempJelly.getX() + tempJelly.getWidth()*80/100 <= face
								&& tempJelly.getY() + tempJelly.getWidth()*20/100 >= c1.getY() + c1.getHeight()*1/3
								&& tempJelly.getY() + tempJelly.getWidth()*80/100 <= foot
								&& tempJelly.getImage() != jellyEffectIc.getImage()) {
								
								tempJelly.setImage(jellyEffectIc.getImage()); // 젤리의 이미지를 이펙트로 바꾼다
								resultScore = resultScore + tempJelly.getScore(); // 총점수에 젤리 점수를 더한다
								
							}
						}
					}
					
					// 장애물위치를 - 4 씩 해준다.
					for (int i = 0; i < tacleList.size(); i++) {
						
						Tacle tempTacle = tacleList.get(i); // 임시 변수에 리스트 안에 있는 개별 장애물을 불러오자
						
						if(tempTacle.getX() < -90) { 
							
							fieldList.remove(tempTacle); // 장애물의 x 좌표가 -90 미만이면 해당 젤리를 제거한다.(최적화)
							
						} else {
							
							tempTacle.setX(tempTacle.getX() - gameSpeed);	// 위 조건에 해당이 안되면 x좌표를 줄이자
							
							face = c1.getX() + c1.getWidth(); // 캐릭터 정면 위치 재스캔
							foot = c1.getY() + c1.getHeight(); // 캐릭터 발 위치 재스캔
							
							if( // 무적상태가 아니고 슬라이드 중이 아니며 캐릭터의 범위 안에 장애물이 있으면 부딛힌다
									!c1.isInvincible()
									&& c1.getImage() != slideIc.getImage()
									&& tempTacle.getX() + tempTacle.getWidth()/2 >= c1.getX()
									&& tempTacle.getX() + tempTacle.getWidth()/2 <= face
									&& tempTacle.getY() + tempTacle.getHeight()/2 >= c1.getY()
									&& tempTacle.getY() + tempTacle.getHeight()/2 <= foot) {
								
								hit(); // 피격 + 무적 쓰레드 메서드
								
							} else if( // 슬라이딩 아닐시 공중장애물
									!c1.isInvincible()
									&& c1.getImage() != slideIc.getImage()
									&& tempTacle.getX() + tempTacle.getWidth()/2 >= c1.getX()
									&& tempTacle.getX() + tempTacle.getWidth()/2 <= face
									&& tempTacle.getY() <= c1.getY()
									&& tempTacle.getY() + tempTacle.getHeight()*95/100 > c1.getY()) {
								
								
								hit(); // 피격 + 무적 쓰레드 메서드
								
							}else if( // 무적상태가 아니고 슬라이드 중이며 캐릭터의 범위 안에 장애물이 있으면 부딛힌다
									!c1.isInvincible()
									&& c1.getImage() == slideIc.getImage()
									&& tempTacle.getX() + tempTacle.getWidth()/2 >= c1.getX()
									&& tempTacle.getX() + tempTacle.getWidth()/2 <= face
									&& tempTacle.getY() + tempTacle.getHeight()/2 >= c1.getY() + c1.getHeight()*2/3
									&& tempTacle.getY() + tempTacle.getHeight()/2 <= foot) {
								
								hit(); // 피격 + 무적 쓰레드 메서드
								
							} else if( // 슬라이딩시 공중장애물
									!c1.isInvincible()
									&& c1.getImage() == slideIc.getImage()
									&& tempTacle.getX() + tempTacle.getWidth()/2 >= c1.getX()
									&& tempTacle.getX() + tempTacle.getWidth()/2 <= face
									&& tempTacle.getY() < c1.getY()
									&& tempTacle.getY() + tempTacle.getHeight()*95/100 > c1.getY() + c1.getHeight()*2/3) {
								
								hit(); // 피격 + 무적 쓰레드 메서드
							}
						}
					}
					
					// 쿠키가 밟을 발판을 계산하는 코드
					int tempField; // 발판위치를 계속 스캔하는 지역변수
					int tempNowField; // 캐릭터와 발판의 높이에 따라 저장되는 지역변수, 결과를 nowField에 저장한다
					
					
					// 쿠키가 무적상태라면 낙사 하지 않기 때문에 400으로 세팅 / 무적이 아니라면 2000(낙사지점);
					if (c1.isInvincible()) {
						tempNowField = 400;
					} else {
						tempNowField = 2000;
					}

					for (int i = 0; i < fieldList.size(); i++) { // 발판의 개수만큼 반복

						int tempX = fieldList.get(i).getX(); // 발판의 x값

						if (tempX > c1.getX()-60 && tempX <= face) { // 발판이 캐릭 범위 안이라면 

							tempField = fieldList.get(i).getY(); // 발판의 y값을 tempField에 저장한다

							
							foot = c1.getY() + c1.getHeight(); // 캐릭터 발 위치 재스캔
							
							// 발판위치가 tempNowField보다 높고, 발바닥 보다 아래 있다면
							// 즉, 캐릭터 발 아래에  제일 높이 있는 발판이라면 tempNowField에 저장한다.
							if (tempField < tempNowField && tempField >= foot) {

								tempNowField = tempField;

							}
						}
					}

					nowField = tempNowField; // 결과를 nowField에 업데이트 한다.
					
					
					
					if(escKeyOn) { // esc키를 누르면 게임이 멈춘다
						while (escKeyOn) {
							try {
								Thread.sleep(10);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
					
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
			}
		}).start();
	}

 

설명

 

맵이동 메서드

맵이동 메서드는 쓰레드를 하나 새로 생성한다.

 

캐릭터 체력 자연감소

맵을 일정거리 이상 이동하면 캐릭터의 체력이 깎이도록 하였다.

 

배경 이동

같은 배경을 무한 반복하는 내용이다.

1번째 배경이 -(배경넓이)가 되면 2번째 배경이 X좌표 0으로 오게될테니 2번째 배경 뒤쪽으로 옮기는 식이다.

배경은 느리게 흐르기 때문에 게임속도의 1/3만 해주었다.

 

발판 이동

발판과 젤리, 장애물은 같은량을 움직인다. 참고하자.

발판리스트에서 발판을 하나씩 가져와서 화면 밖으로 나간 발판은 최적화를 위해 제거해주고

그렇지 않은 발판은 게임속도에 맟춰서 왼쪽으로 이동시킨다.

 

젤리 이동 및 동작

젤리는 장판과 비슷하지만, 캐릭터가 젤리를 먹는 이벤트가 있다.

젤리를 먹는 조건은 위와 같다.

캐릭터의 발위치를 확인한 뒤

젤리 획득범위를 넓게하고 싶다면

20/100을 1/100 가까이로 줄이면되고, 80/100을 100/100 가까이로 늘이면된다.

슬라이딩을 하는경우 높이가 낮아지기 때문에 Y값에다가 캐릭터의 높이의 1/3을 더해주었다.

 

 

장애물 이동 및 동작

장애물은 코드가 너무 길어 접은글로 올렸다

더보기
					// 장애물위치를 - 4 씩 해준다.
					for (int i = 0; i < tacleList.size(); i++) {
						
						Tacle tempTacle = tacleList.get(i); // 임시 변수에 리스트 안에 있는 개별 장애물을 불러오자
						
						if(tempTacle.getX() < -90) { 
							
							fieldList.remove(tempTacle); // 장애물의 x 좌표가 -90 미만이면 해당 젤리를 제거한다.(최적화)
							
						} else {
							
							tempTacle.setX(tempTacle.getX() - gameSpeed);	// 위 조건에 해당이 안되면 x좌표를 줄이자
							
							face = c1.getX() + c1.getWidth(); // 캐릭터 정면 위치 재스캔
							foot = c1.getY() + c1.getHeight(); // 캐릭터 발 위치 재스캔
							
							if( // 무적상태가 아니고 슬라이드 중이 아니며 캐릭터의 범위 안에 장애물이 있으면 부딛힌다
									!c1.isInvincible()
									&& c1.getImage() != slideIc.getImage()
									&& tempTacle.getX() + tempTacle.getWidth()/2 >= c1.getX()
									&& tempTacle.getX() + tempTacle.getWidth()/2 <= face
									&& tempTacle.getY() + tempTacle.getHeight()/2 >= c1.getY()
									&& tempTacle.getY() + tempTacle.getHeight()/2 <= foot) {
								
								hit(); // 피격 + 무적 쓰레드 메서드
								
							} else if( // 슬라이딩 아닐시 공중장애물
									!c1.isInvincible()
									&& c1.getImage() != slideIc.getImage()
									&& tempTacle.getX() + tempTacle.getWidth()/2 >= c1.getX()
									&& tempTacle.getX() + tempTacle.getWidth()/2 <= face
									&& tempTacle.getY() <= c1.getY()
									&& tempTacle.getY() + tempTacle.getHeight()*95/100 > c1.getY()) {
								
								
								hit(); // 피격 + 무적 쓰레드 메서드
								
							}else if( // 무적상태가 아니고 슬라이드 중이며 캐릭터의 범위 안에 장애물이 있으면 부딛힌다
									!c1.isInvincible()
									&& c1.getImage() == slideIc.getImage()
									&& tempTacle.getX() + tempTacle.getWidth()/2 >= c1.getX()
									&& tempTacle.getX() + tempTacle.getWidth()/2 <= face
									&& tempTacle.getY() + tempTacle.getHeight()/2 >= c1.getY() + c1.getHeight()*2/3
									&& tempTacle.getY() + tempTacle.getHeight()/2 <= foot) {
								
								hit(); // 피격 + 무적 쓰레드 메서드
								
							} else if( // 슬라이딩시 공중장애물
									!c1.isInvincible()
									&& c1.getImage() == slideIc.getImage()
									&& tempTacle.getX() + tempTacle.getWidth()/2 >= c1.getX()
									&& tempTacle.getX() + tempTacle.getWidth()/2 <= face
									&& tempTacle.getY() < c1.getY()
									&& tempTacle.getY() + tempTacle.getHeight()*95/100 > c1.getY() + c1.getHeight()*2/3) {
								
								hit(); // 피격 + 무적 쓰레드 메서드
							}
						}
					}

 

장애물은 경우의 수는 아래와 같다.

1. 달리는 중 아래에 있는 장애물
2. 달리는 중 머리 위에 있는 장애물
3. 슬라이드 중 아래에 있는 장애물
4. 슬라이드 중 머리 위에 있는 장애물

캐릭터는 장애물에 부딛히면 캐릭터가 데미지를 입고 깜빡이며 3초간 무적상태가 된다.(추후 hit() 메서드 추가)

그러므로 무적상태가 아닐때 충돌이 발생해야한다.(!c1.isInvincible())
또한 이미지가 슬라이드 중인지 달리는 중인지 구분하고
(downKeyOn으로 구분하게 되면 공중에서 다운키를 눌러서 범위를 줄일 수 있게된다.)

장애물은 커보이지만 피격범위가 좁기때문에 (이용자 배려인듯)

x값은 장애물 넓이의 정중앙으로

y값도 높이의 정중앙으로 범위를 정했다.

공중장애물은 캐릭터 머리와 만나기 때문에 높이의 95퍼센트 까지로 지정하였다.

데미지를 입지 않는다면 96~99퍼센트 까지 조정해보자.

 

발판 계산

쿠키가 밟을 발판을 계산하는 코드이다.

예를들어 발판이 없고 무적이라면 최저바닥이 400으로서 낙사하지 않는다.

발판이 없고 무적이 아니라면 바닥은 2000으로 화면 밖으로 나가 낙사하게 된다.

그 경우가 아니라면 발판들을 모두 스캔해서 캐릭터가 달리고 있는 위치의 발판만 추려 낸뒤

제일 높은 곳에 있는 발판의 위치를 업데이트한다.

예를들어 Y값을 기준으로 400위치에만 발판이 하나 있고 캐릭터가  300위치에 있다면 nowField는  400

400위치 200위치 두 곳에 발판이 있는데

캐릭터가 100에 있다면 200이 발판이 되며 캐릭터가 300에 있다면 400이 발판이 된다
(머리위에 있는 발판으로 떨어질 수는 없지 않은가.)

 

esc관련 코드

esc를 누르면 위의 모든 코드들이 중지되고 esc를 다시누를 때까지 대기한다.

 

while문이기 때문에 0.01초정도 간격을 준다 (주지 않으면 리소스 사용량이 폭증한다.)

 

다음편에 계속

+ Recent posts