코딩항해기

[Team] Pokemon 게임 만들기 본문

Project

[Team] Pokemon 게임 만들기

miniBcake 2024. 7. 11. 12:24

 

Pokemon 게임 만들기

java / Eclipse

4인참여 (팀장직 수행)

240705 ~ 240711

 

java 상속, 오버라이딩 연습을 위한 팀 프로젝트를 진행하였다.

 


 

[요구사항]

 

[포켓몬스터 게임 프로그램을 작성해주세요]

class 포켓몬 String 타입 // 모든 포켓몬은 타입이 반드시 존재한다. ex) 전기, 물, ...

String 이름 // 모든 포켓몬은 이름이 반드시 존재한다. ex) 피카츄, 꼬부기, ...

int 레벨 // 새로 잡은 포켓몬의 레벨은 1~5 랜덤한 값을 가진다.

int 경험치 // 새로 잡은 포켓몬의 경험치는 0이다.

void attack() // 50%의 확률로 성공 -> 성공시 50~500 사이의 경험치 획득

void hello() // 피카츄는 삐까삐까, 꼬부기는 꼬북꼬북 등의 울음소리를 출력한다.

void levelUp() // 경험치가 100을 채울때마다 레벨은 +1

 

class 피카츄

attack() // 전기타입 -> 전기충격

hello() // 삐까삐까

 

class 꼬부기

attack() // 물타입 -> 물대포

hello() // 꼬북꼬북

 

syso(포켓몬객체); 수행시 [피카츄 전기타입 Lv5 exp10]으로 출력

  1. 게임하기 2. 전체상태출력 3. 울음소리듣기 4. 포켓몬잡기 0. 게임종료

# 피카츄,꼬부기 대신 다른 포켓몬들로 구현할 것!

# 요구사항을 벗어나지않는 조건에서 기능 및 설정 추가 가능!

  1. 게임하기를 누르면
  2. 포켓몬 중 하나를 고름
  3. 공격
  4. 성공을 하면 레벨업
  5. 포켓몬 잡기는 create

 

[패키지, 클래스명 설정]

    타입 공격 울음소리
패키지명 teamproject      
메인클래스명 PokemonGame      
포켓몬 Pokemon      
Myu 에스퍼 염동력
쥬쥬 Jyujyu 아쿠아링 쥬쥬
두두 Dudu 노멀 박치기 두두

 

 

[로직구성]

더보기
  1. 프로그램 종료 전까지 반복함
  2. 메뉴출력
  3. 입력값 받기
  4. 입력값 검증
  5. 게임종료라면 프로그램 종료, 반복 종료
  6. 게임하기라면
    1. 포켓몬을 소유하고 있는지 확인
      1. 소유하고있다면,
        1. 포켓몬 중 하나를 고름 (=전체출력메소드)
        2. 올바른 값을 입력받을 때까지 반복함
        3. 공격 진행 할지 확인하기
        4. 공격 진행
          1. 성공이라면 경험치 (50~500) 랜덤 부여
          2. 레벨업
        5. 성공실패 여부와 경험치, 레벨 내용 출력
      2. 소유하고 있는 포켓몬이 없다면
        1. 없다고 안내 + 포켓몬 잡으라고 안내
  7. 전체 상태 출력이라면,
    1. 소유하고 있는 포켓몬이 있는지 확인
      1. 있다면
        1. 소유하고 있는 포켓몬의 상태 전체 출력 (toString)
      2. 없다면 없다고 안내
  8. 울음소리 듣기라면
    1. 포켓몬을 소유하고 있는지 확인
      1. 소유하고 있다면,
        1. 포켓몬 중 하나를 고름 (=전체출력)
        2. 옳은 값을 입력할 때까지 반복
        3. 울음소리 출력
      2. 소유하고 있는 포켓몬이 없다면
        1. 없다고 안내
  9. 포켓몬 잡기 라면
    1. 저장할 공간이 있는지 확인
    2. 있다면,
      1. 포켓몬 객체 랜덤 저장
      2. 저장한 객체 안내
    3. 없다면,
      1. 더 이상 잡을 수 없다고 안내
  10. 선택지에 없는 값이라면
    1. 올바른 입력값에 대해 안내
  11. 선택지의 내용을 실행했다면 다시 메뉴출력부터 반복

 

[파트분배]

전체메뉴 구성 + 소유여부(메소드) + 1차 취합 aaa
전투하기 (=게임하기) bbb
포켓몬잡기 (포켓몬객체저장) miniBcake (팀장)
포켓몬정보, 울음소리 출력+클래스(메소드부분) ccc

 

 

[코드흐름도-상세]

파트 담당자들이 각자 파트 작성

더보기

[main 한글코딩]

스캐너 선언

  1. 프로그램 종료 전까지 반복함(무한 반복)
  2. while(무한 반복)
  3. 메뉴출력★☆★포켓몬 게임★☆★ϞϞ(๑◕ܫ◕๑) ( U U) U U
    1. 게임종료
    2. 게임시작
    3. 전체 상태 출력
    4. 울음소리 듣기
    5. 포켓몬 잡기
    ===================
  4. ===================
  5. (),,,()
  6. ===================
  7. 입력값 선언
  8. 메뉴값 초기화
  9. 입력값 받기 및 검증(유효성 검사)메뉴값 입력받기
  10. while 똑바로 입력할때까지 입력하기(무한 반복)
  11. 게임종료라면 프로그램 종료, (반복 종료)종료
  12. if(만약에 menu가 0이라면)
  13. 게임하기라면
    1. 포켓몬을 소유하고 있는지 확인
      1. 소유하고있다면,
      2. 소유중인 포켓몬 배열 생성; 최대 6마리
      3. 초기 배열 ‘0’;
        • 메뉴 4번
        while 반복문 사용 (공격을 한 후에 다시 재공격 옵션 있을시)‘boolean flag=true’로 종료 조건도 미리 준비 & 종료조건
      4. if문 사용(단발성 공격일땐)
      5. 포켓몬 없이는 공격이 안되므로 없는 플레이어는 잡고 오도록 유도
      6. 보유중인 포켓몬 데이터 전부 제시하고(선택할 수 있도록)
      7. “입력하십시요”
      8. for 반복문으로 (선택한 번호 와 맞는 ’포켓몬’ )
        1. 리스트 println(); 배열 리스트 변수 활용해서 출력문 작성
      String[] myPokeList==================정수 입력syso”hello();”
      1. 올바른 값을 입력받을 때까지 반복함if (int ≤0 && int>myPokeList.length){ 총 6마리 보유가능)
        1. 공격, 2. 포켓몬 재선택, 그 외 옵션 (종료 ‘flag=false’)
      2. 입력받은 정수 유효성 검사
      3. 공격 진행 할지 확인하기sc.nextInt() 1 = Y / 2 = N안한다면 포켓몬 고르는 메뉴로 if(i=2){
      4. continue;}
      5. ‘1’ = 1-4. 공격진행으로
      6. syso “이 포켓몬으로 공격 진행하겠습니까?”
      7. 공격 진행 (attack())
        1. int randomAtt 변수 선언
        2. randomATT는 랜덤 값을 2까지로 설정해서 50% 확률로 공격 설정 1 or 2 랜덤
        3. 1이면 성공하면 ???
        4. int randomExp 변수 선언
        5. randomExp의 값을 50~500까지 수중에 랜덤으로 준다.
        6. 만약에 경험치가 this.exp + randomExp >100 이상이라면
          1. randomExp를 100으로 나누어서 몫의 값(levelCount)을 levelUp() 인자로 보내서 더해주는 함수를 실행하고 !!
          2. this.exp + randomExp에서 levelCount*100의 값을 빼준값을 this.exp에 저장시킨다.
        7. 만약에 this.exp + randomExp <100 이하
          1. 레벨업함수를 실현시키지 않고, randomExp의값을 this.exp에 더해서 this.exp에 저장 시킨다.
        8. 얼마만큼 경험치가 상승했는지 출력해준다.
      8. 성공실패 여부와 경험치, 레벨 내용 출력(levelUp())
        1. levelUp()함수에 levelCount(int i)라는 인자를 받아서
        2. level라는 멤버변수를 level멤버변수+i 라고 설정한다.
        3. 몇만큼 레벨업되었는지 출력해주고 현재레벨을 출력해준다.
      9. 소유하고 있는 포켓몬이 없다면
        1. 없다고 안내 + 포켓몬 잡으라고 안내
    2. sc.nextInt();
    3. ==================
    4. syso 배열 출력
  14. if(만약에 menu가 1이라면)
  15. 전체 상태 출력이라면,
    1. 소유하고 있는 포켓몬이 있는지 확인
      1. mypoke 배열안에 있다면 인자가 있다면
        1. 소유하고 있는 포켓몬의 상태를 반복문을 사용해서 전체 출력 (toString)
      2. 없다면 없다고 안내
  16. if(만약에 menu가 2이라면)
  17. 울음소리 듣기라면
    1. 포켓몬을 소유하고 있는지 확인
      1. 소유하고 있다면,
        1. 포켓몬 중 하나를 고름
        2. 옳은 값을 입력할 때까지 반복
        3. 울음소리 출력
      2. 소유하고 있는 포켓몬이 없다면
        1. 없다고 안내
  18. if(만약에 menu가 3이라면)
  19. 포켓몬 잡기 라면
    1. 저장할 공간이 있는지 확인
    2. 있다면,
      1. 랜덤값 (0~99) 설정
      2. if(랜덤값이 55~99 이라면) { 배열 = 두두 객체 저장} 45%
      3. else if(랜덤값이 10~54 이라면) { 배열 = 쥬쥬 객체 저장} 45%
      4. elseif(랜덤값이 0~9 이라면) { 배열 = 뮤 객체저장} 10%
      5. syso([피카츄 전기타입 Lv5 exp10]을 잡았습니다!) (디벨롭:메뉴선택으로 잡기)
      6. 5개의 잡을 수 있는 포켓몬을 저장할 수 있는 배열 생성
      7. 포켓몬 확률 지정
      8. 포켓몬 확률을 전부 더한 값이 100이 아니라면 프로그램 진행불가 (continue) 안내 (개발자 잘못)
      9. for (잡을 수 있는 포켓몬 배열 길이만큼 반복하기) {
      10. 랜덤값 (0~99) 설정
      11. if(랜덤값이 두두 범위 내라면) { 배열 = 두두 객체 저장} 45%
      12. else if(랜덤값이 쥬쥬 범위 내라면) { 배열 = 쥬쥬 객체 저장} 45%
      13. else if(랜덤값이 뮤 범위 내라면) { 배열 = 뮤 객체저장} 10%
      14. }
      15. 배열을 반복하여 랜덤으로 설정된 잡을 수 있는 포켓몬 이름을 출력 (0을 입력하면 메뉴로 돌아가기)
      16. int subMenu = 사용자 입력받기
      17. subMenu가 0~5 사이의 값일때까지 반복함
      18. if (subMenu가 0이라면){메뉴로 돌아감(break;)}
      19. else if (범위의 값이라면) {
      20. 랜덤값 (0~99) 지정
      21. 확률(82%) 기준 지정
        1. if 잡기에 성공하면 (랜덤값이 확률보다 작다면)
          1. 선택한 번호-1에 맞는 배열값을 불러와 사용자 소유 포켓몬 배열에 저장함
          2. syso([피카츄 전기타입 Lv5 exp10]을 잡았습니다!)
        2. else 잡기에 실패하면 (랜덤값이 확률과 같거나 크다면)
          1. syso([피카츄 전기타입 Lv5 exp10]을 놓쳤습니다…)
      22. }
      23. else{syso 올바른 입력값 안내 }
    3. 없다면,
      1. 더 이상 잡을 수 없다고 안내
  20. if(만약에 menu가 4이라면)
  21. 선택지에 없는 값이라면
    1. 올바른 입력값에 대해 안내
  22. if(만약에 menu가 이상하다면)
  23. 선택지의 내용을 실행했다면 다시 메뉴출력부터 반복

[메소드, 함수 한글코딩]

유효성검사 함수

FullPoke (내가 가진 포켓몬(cnt)가 내 가방에 가득 찼을때(Pokemon[] myPokeList)) 만약 내가가진 포켓몬수가 내 가방보다 크다면 포켓몬을 최대로 소유하고 있습니다.

NoPoke (내가 가진 포켓몬(cnt)가 0보다 작을때) 소유하고 있는 포켓몬이 없습니다.

 

[코드]

package teamproject;

import java.util.Random;
import java.util.Scanner;

class Pokemon {
	String type; // 모든 포켓몬은 타입이 반드시 존재한다. ex) 전기, 물, ...
	String name; // 모든 포켓몬은 이름이 반드시 존재한다. ex) 피카츄, 꼬부기, ...
	int level; // 새로 잡은 포켓몬의 레벨은 1~5 랜덤한 값을 가진다.
	int exp; // 새로 잡은 포켓몬의 경험치는 0이다.

	static Random rand = new Random();

	Pokemon(String type, String name) {
		this.type = type;
		this.name = name;
		this.level = rand.nextInt(5) + 1;
		this.exp = 0;
	}

	void attack() {
		// 50%의 확률로 성공 -> 성공 시 50~500 사이의 경험치 획득

		// 50% 확률로 공격 설정
		int randomAtt = Pokemon.rand.nextInt(2); // 0 or 1

		if (randomAtt == 0) { // 공격 성공
			System.out.println("공격에 성공하였습니다.");
			
			int minExp = 50;
			int maxExp = 500;

			// 50~500 사이의 랜덤 경험치 획득
			int randomExp = Pokemon.rand.nextInt(maxExp - minExp + 1) + minExp; // 50 ~500 사이
			int newExp = this.exp + randomExp; // 총 경험치 합

			if (newExp >= 100) {
				// 레벨업 처리
				int levelCount = newExp / 100; // 레벨업 카운트
				this.exp = newExp % 100; // 남은 경험치
				this.levelUp(levelCount); // 레벨업 메서드 실행
				System.out.println(levelCount + " 만큼 레벨업하였습니다.");
			} else {
				// 경험치 추가
				this.exp = newExp; // 100이 안될경우 그냥 경험치 저장
				System.out.println(this.exp + " 경험치가 올랐습니다.");
			}
		} else {
			// 공격 실패
			System.out.println("공격에 실패하였습니다.");
		}
	}

	void hello() {
		// 피카츄는 삐까삐까, 꼬부기는 꼬북꼬북 등의 울음소리를 출력한다.
		System.out.println("힝~");
	}

	void levelUp(int i) {
		// 경험치가 100을 채울때마다 레벨은 +1
		this.level = this.level + i;
	}

	@Override
	public String toString() {
//		[피카츄 전기타입 Lv5 exp10]
		return "["+ this.name +" "+ this.type +"타입 Lv."+ this.level+" exp."+ this.exp + "]";
	}

}

class Myu extends Pokemon {
	Myu() {
		super("에스퍼", "뮤");
	}

	@Override
	void hello() {
		System.out.println("뮤뮤뮤");
	}
}

class Jyujyu extends Pokemon {
	Jyujyu() {
		super("물", "쥬쥬");
	}

	@Override
	void hello() {
		System.out.println("쮸쮸쮸");
	}
}

class Dudu extends Pokemon {
	Dudu() {
		super("노멀", "두두");
	}

	@Override
	void hello() {
		System.out.println("뚜뚜뚜");
	}
}


public class PokemonGame {

	public static boolean isEmpty(int cnt) {
		if (cnt <= 0) {
			System.out.println("소유한 포켓몬이 없습니다!");
			return true;
		}
		return false;
	}

	public static boolean isFull(int cnt, Pokemon[] datas) {
		if (cnt >= datas.length) {
			System.out.println("더이상 포켓몬을 소유할 수 없습니다!");
			return true;
		}
		return false;
	}

	public static void main(String[] args) {

		Random rand = new Random();
		Scanner sc = new Scanner(System.in);

		//변수
		int menu; //메뉴값입력
		int cnt=0; //저장되어있는 포켓몬 수
		Pokemon[] myPokeList = new Pokemon[6]; //내포켓몬 저장할 배열

		while (true) {
			System.out.println("===================\n"
		               + " ★☆★포켓몬 게임★☆★\n"
		               + "   (),,,()\n"
		               + " ϞϞ(๑◕ܫ◕๑)\n"
		               + "   ( U U)\n"
		               + "    U U\n"
		               + "===================\n"
		               + "0. 게임종료\n"
		               + "1. 전투시작\n"
		               + "2. 전체 상태 출력\n"
		               + "3. 울음소리 듣기\n"
		               + "4. 포켓몬 잡기\n"
		               + "===================");
			System.out.println();
			while (true) {
				System.out.print("메뉴를 입력해주세요 : ");
				menu = sc.nextInt();
				if (menu >= 0 && menu <= 4) {
					break;
				}
				else{
					System.out.println("잘못된 입력입니다.");
					System.out.print("다시 입력하세요 >>");
					continue;
				}
			}
			if (menu == 0) {
				System.out.println("게임을 종료합니다.");
				break;
			}
			else if (menu == 1) {//전투
				if(isEmpty(cnt)) {
					continue;
				}
				
				while (true) {
					System.out.println("====================");
					System.out.println("함께할 포켓몬을 골라주세요!");
					System.out.println("====================");

					for (int i = 0; i < cnt; i++) { // 현재 보유한 포켓몬 리스트 출력
						System.out.println((i + 1) + ". " + myPokeList[i].name);
					}

					System.out.println("====================");

					System.out.print("어떤 포켓몬을 선택하시겠습니까? 이름 옆 번호를 입력해주세요! : ");
					int choice = sc.nextInt(); // 선택할 포켓몬 번호 입력

					if (choice > 0 && choice <= cnt) { // 유효성 검사
						Pokemon selectedPoke = myPokeList[choice - 1]; // (입력값 -1) 선택한 포켓몬 객체
						System.out.println("선택한 포켓몬: " + selectedPoke.name);

						System.out.println("이 포켓몬으로 공격하시겠습니까? (1: 공격 / 2: 포켓몬 선택 / 0: 종료)");
						System.out.print("숫자 입력 : ");
						int attPoke = sc.nextInt(); // 공격 여부 입력 받고

						if (attPoke == 1) {
							selectedPoke.attack(); // 공격 = 1
						}
						else if (attPoke == 2) {
							System.out.println("포켓몬을 다시 선택합니다."); // 포켓몬 재선택 = 2
						}
						else if (attPoke == 0) {
							System.out.println("전투를 종료합니다.");
							break; // 1, 2 외의 답 = 게임종료 플래그
						}
						else {
							System.out.println("잘못된 입력입니다. 다시 선택해주세요.");
						}
					}
					else {
						System.out.println("잘못된 입력입니다. 다시 선택해주세요."); // 유효성 검사
					}

					System.out.println("====================");
					System.out.println("공격을 계속하시길 원하시면 '1'을 눌러주세요!");
					System.out.println("숫자로 입력해주세요! 그 외의 답은 전투를 종료시킵니다!");
					int again = sc.nextInt(); // 게임 계속 여부 입력
					if (again != 1) { // 1 아닐때 반복 종료.
						break; // 게임 종료 플래그 설정
					}
				}// 여기까지가 'while'반복문 걸리는 곳.
				System.out.println("전투를 종료합니다."); // 게임 종료 메시지
			}
			else if (menu == 2) {//가지고 있는 전체 포켓몬 정보
				if(isEmpty(cnt)) {
					continue;
				}
				
				for(int i=0;i<cnt;i++) {
					System.out.println(myPokeList[i]);
				}
			} 
			else if (menu == 3) {//선택한 포켓몬 울음소리 출력
				if(isEmpty(cnt)) {
					continue;
				}
				//울음소리 출력
				System.out.println("포켓몬 이름을 입력하세요");
				String findName = sc.next();
				boolean found = false;
				for (int i = 0; i < cnt; i++) {
					if(findName.equals(myPokeList[i].name)) {
						myPokeList[i].hello();// 중복출력 제거 
						found= true;
						break;
					}

				}
				if(!found) {
					System.out.println("해당 포켓몬이 없어서 울지못해요");
				}

			} 
			else if (menu == 4) {
				if(isFull(cnt, myPokeList)) {
					continue;
				}
				
				int subMenu;//메뉴 입력값
				Pokemon[] catchPoke = new Pokemon[5];
				//메뉴로 제공할 포켓몬 5마리 리스트 만들기
				//확률지정 myuProb + jyujyuProb + duduProb 총합 100이 되어야함
				int myuProb = 2; //뮤 출현 확률
				int jyujyuProb = 49; //쥬쥬 출현 확률
				int duduProb = 49; //두두 출현 확률
				int prob = 89; //잡기성공확률 지정 (0(완전불가)~100(무조건성공))

				//확률 검증 (확률지정에 오류가 있다면 프로그램이 실행되지 않음)
				if(!(myuProb + jyujyuProb + duduProb == 100)) {
					//확률 총합이 100이 아니게 설정해놓았을 때 실행되는 코드 (개발자 확인용)
					System.out.println("-===[오류발생]===-");
					System.out.println("포켓몬 확률 지정에 오류가 있어 프로그램을 실행할 수 없습니다.");
					System.out.println((myuProb + jyujyuProb + duduProb)+" != 100");
					continue;
				}
				for(int i=0;i<catchPoke.length;i++) {//배열 길이만큼 반복하여 저장
					int randNum = rand.nextInt(100);
					//확률에 따라 두두 쥬쥬 뮤를 저장함
					if(myuProb+jyujyuProb < randNum && randNum < 100) {//두두
						catchPoke[i] = new Dudu();
					}
					else if(myuProb < randNum && randNum <= myuProb+jyujyuProb) {//쥬쥬
						catchPoke[i] = new Jyujyu();
					}
					else if(0 <= randNum && randNum <= myuProb) {//뮤
						catchPoke[i] = new Myu();
					}
				}//for(int i=0;i<catchPoke.length;i++)
				while(true) {//올바른 값을 입력받을 때까지 입력값을 반복하는 반복문
					System.out.println("☆*: .。. _ .。.:*☆");
					for(int i=0; i<catchPoke.length; i++) {
						System.out.println((i+1)+". "+catchPoke[i].name+", "+catchPoke[i].type+" 타입");
					}
					System.out.println("☆*: ˙\"˙ - ˙\"˙:*☆");
					System.out.println("0. 메뉴로 돌아가기");
					System.out.print("번호 선택 >> ");
					subMenu = sc.nextInt();//메뉴 입력값 받기

					if(subMenu == 0) {// 메뉴로 돌아가기
						break;
					}
					else if (1<= subMenu && subMenu <= catchPoke.length){ //출현한 포켓몬 수의 범위
						int randNum = rand.nextInt(100);
						if(randNum < prob) {//잡는데 성공함!!
							myPokeList[cnt++] = catchPoke[subMenu-1];
							System.out.println(catchPoke[subMenu-1]+" 을 잡았습니다!");
							break;
						}
						else {//잡는데 실패함
							System.out.println(catchPoke[subMenu-1]+" 을 놓쳤습니다...");
							break;
						}
					}
					else { //메뉴 외의 입력값
						System.out.println("올바른 입력값을 입력해주세요.");
					}
				}//while
				//포켓몬 잡기 종료
			}
		}
	}
}

 

 

[후기]

포켓몬 잡기를 할 때 선택지부터 new연산자를 사용해 객체로 보여주기 때문에 메모리를 낭비하는 부분이 있었다.

이 부분을 프로젝트 마무리 전에 보완할 수 있었다면 좋았을 것 같다.

포켓몬 게임에 대해서도 좀 더 연구했다면 더 좋은 결과물을 낼 수 있었을 것 같다.