[JAVA] 포켓몬 게임 프로젝트
JAVA를 이용하여 약 5일간의 프로젝트를 만들어보았다.자세한 과정과 내용은 아래 노션에다가 기록해놓았다. ↓ ↓ ↓ ↓ ↓https://www.notion.so/TeamProject-e27a469100534f86843b034b4dca48ad TeamProject | Notion멤
yn98.tistory.com
이전 글에서 완성된 포켓몬 게임 프로젝트이다.
사실 위 글의 코드는 접근제어자와 추상메서드를 이용하지 않았다. -> 이는 객체지향을 완전히 살렸다고 볼 수 없는 코드이다.
피드백받았던 부분을 수정하였고, 오탈자도 수정하고, 객체지향의 특징을 살려서 코드를 다시 짜보았다.
package class02;
import java.util.Random;
import java.util.Scanner;
abstract class Pokemon{
/*멤버변수선언 */
private String type; // 타입 (강제)
private String name; // 이름 (강제)
private int level; // 레벨
private int exp; // 경험치
/*클래스변수 선언*/
static final int attackExpMin = 50; // 공격 성공 시 추가되는 최소 경험치
static final int attackExpMax = 500; // 공격 성공 시 추가되는 최대 경험치
static Random rand = new Random();
static final int maxLevel =30;
// 생성자
Pokemon(String type,String name) { //초기화
this.type = type;
this.name = name;
this.level = rand.nextInt(5)+1; // 1에서 5까지 레벨
this.exp = 0;
}
// 함수
boolean attack(){ // attack 메서드
// 공격 50% 확률로 성공
attackVoice(); // 기술명 외침 ex ) 전기공격!
hello(); // 울음소리 ex) 삐까삐까!
if(rand.nextDouble() < 0.5 ){// 공격에 성공했을 경우 - 50%확률, random 함수는 0~1 사이를 랜덤값 반환하니까!
int attackExp = rand.nextInt(attackExpMax - attackExpMin + 1) + attackExpMin;
// attackExpMin에서 attackExpMax 사이의 랜덤한 경험치 획득
this.exp += attackExp; // 현재 경험치에 방금 획득한 경험치를 증가시킴
if(this.level >= maxLevel) { // 이미 만렙인 경우
System.out.println(this.name+"은(는) 만렙을 달성해서 더이상 경험치를 획득할 수 없습니다!");
this.exp = 0; // 만렙은 exp = 0 으로 고정함
return true; // 만렙을 달성했기 때문에 true 반환
}
System.out.println(this.name + " 공격 성공! " + attackExp + " 의 경험치 획득 !");
while (this.exp >= 100) { // 경험치가 100 이상이 되면
levelUp();// 레벨업 메서드 실행
}
return true;// 레벨업이 없는경우
}
else{ // 공격에 실패했을 경우
System.out.println("공격에 실패했습니다.");
}
return false;
}
void levelUp(){ // levelUp 메서드
int additionalLevels = this.exp / 100; // 현재 경험치를 100으로 나눈 몫을 추가 레벨로 설정
this.level += additionalLevels; // 포켓몬의 레벨을 추가 레벨만큼 증가
this.exp %= 100; // 남은 경험치를 100으로 나눈 나머지로 설정하여 경험치 초기화
if (this.level >= maxLevel) { // 레벨이 만렙에 도달한 경우
System.out.println("축하합니다!" + this.name + " 만렙 달성!"); // 만렙 달성 문구 출력
this.level = maxLevel; // 레벨을 최대 레벨(maxLevel)로 설정
this.exp = 0; // 추가 경험치 초기화
return; // 더 이상 경험치를 처리할 필요 없으므로 return
}
else {
// 레벨업 메시지 출력
System.out.println(this.name + "의 레벨 업! 레벨 " + additionalLevels + " 증가! 현재 레벨은" + this.level+" 입니다!");
}
}
abstract void hello(); // 울음소리
abstract void attackVoice(); // 공격할 때 기술명
@Override
public String toString(){//[포켓몬이름,포켓몬타입,포켓몬레벨,포켓몬경험치가 출력되게 설정
return "[ "+this.name+", "+this.type+" 타입 , 현재 레벨 : "+this.level+", 현재 경험치 : "+this.exp+"]";
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public int getExp() {
return exp;
}
public void setExp(int exp) {
this.exp = exp;
}
} // 포켓몬 클래스 닫기
//자식클래스들//
class Ditto extends Pokemon{ // 자식클래스, 메타몽
// 생성자, 타입/이름 고정
Ditto(){
super("노말", "메타몽"); // 부모생성자 호출
}
// 함수
@Override
void hello() { // 울음소리 출력, 오버라이딩
System.out.println("어라?😭");
}
@Override
void attackVoice() { // 공격시 출력되는 attackVoice, 오버라이딩
System.out.print("변신!! ");
}
}
class Zorua extends Pokemon{ // 자식클래스, 조로아
// 생성자, 타입/이름 고정
Zorua(){
super("악", "조로아"); // 부모생성자 호출
}
// 함수
@Override
void hello() { // 울음소리 출력, 오버라이딩
System.out.println("조르륵😭");
}
@Override
void attackVoice() { // 공격시 출력되는 attackVoice, 오버라이딩
System.out.print("물기!! ");
}
}
class Cubone extends Pokemon{ // 자식클래스, 탕구리
// 생성자, 타입/이름 고정
Cubone(){
super("땅", "탕구리"); // 부모생성자 호출
}
// 함수
@Override
void hello() { // 울음소리 출력, 오버라이딩
System.out.println("구리😭");
}
@Override
void attackVoice() { // 공격시 출력되는 attackVoice, 오버라이딩
System.out.print("탕!탕! ");
}
}
class Oddish extends Pokemon{ // 자식클래스, 뚜벅쵸
// 생성자, 타입/이름 고정
Oddish(){
super("풀", "뚜벅쵸"); // 부모생성자 호출
}
// 함수
@Override
void hello() { // 울음소리 출력, 오버라이딩
System.out.println("뚜벅😭");
}
@Override
void attackVoice() { // 공격시 출력되는 attackVoice, 오버라이딩
System.out.print("잎날가르기!! ");
}
}
////////////////
public class Test02{
public static int menu(){ // 메뉴판 출력
System.out.println("★★포켓몬 게임★★");
System.out.println("====== 메 뉴 ======");
System.out.println("1. 게임하기");
System.out.println("2. 전체 상태 출력");
System.out.println("3. 울음소리 듣기");
System.out.println("4. 포켓몬 잡기");
System.out.println("0. 게임종료");
System.out.println("==================");
System.out.print("메뉴를 선택해주세요 >> ");
// 메뉴 선택
int num = getValidInput(0,4);
return num;
}
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) {
return true;
}
return false;
}
/* 포켓몬 선택, 유효성 검사*/
public static int getValidInput(int start, int end) {
Scanner sc = new Scanner(System.in);
int n = 0;
while (true) {
try {
n = Integer.parseInt(sc.nextLine()); // 문자열로 입력받고 정수로 변환
if (start <= n && n <= end) { // 범위 내의 숫자를 알맞게 입력했다면
return n;
} else { // 범위 밖의 숫자를 입력한 경우
System.out.print("잘못된 입력입니다. 다시 선택해주세요 >> ");
}
} catch (NumberFormatException e) { // 숫자가 아닌 문자를 입력한 경우
System.out.print("잘못된 입력입니다. 다시 선택해주세요 >> ");
}
}
}
public static int pokemonMenu(int cnt, Pokemon[] datas) { //
System.out.println("포켓몬을 선택해주세요.");
for (int i = 0; i < cnt; i++) {
System.out.println((i+1)+". " +datas[i]);
}
// 출력된 포켓몬 중 선택
int num = getValidInput(1, cnt);
return num-1; // 배열의 위치를 돌려줌
}
public static void main(String[] args) {
// 포켓몬을 담을 배열 생성
Pokemon[] datas = new Pokemon[3];
int cnt = 0;
Scanner sc = new Scanner(System.in);
// 게임을 끝내기 전까지 무한 반복
while(true) {
// 메뉴 출력 ,선택 함수를 불러 정수값을 받음
int menu = menu();
// 메뉴값에 따른 if문
// 만약 menu가 0이면
if(menu == 0) { // 게임 종료 (맡은 부분)
System.out.println("게임을 종료합니다.");
break;
}
// 만약 menu가 1이면
else if(menu == 1) { // 게임 시작하기 (맡은 부분)
// 지니고 있는 포켓몬이 있는지 확인
if(isEmpty(cnt)) { // 만약 비어있다면
continue;
}
// Y/N 답을 담을 문자열 변수 answer
String answer;
System.out.println("야생 포켓몬이 나타났습니다.");
System.out.print("공격하시겠습니까? (Y/N)");
answer = sc.next();
// 선택할 포켓몬 위치를 담을 변수
int num;
// 만약 공격한다면
if(answer.equals("Y")) {
// 포켓몬을 고름, pokemonMenu
num = pokemonMenu(cnt, datas);
}
// 아니라면 도망
else {
System.out.println("무사히 도망쳤습니다.");
continue;
}
// 실패시 다시 도전하는 프로그램
// 전투 반복
while(true) {
// 공격 시도 attack() 함수
// 공격 실패시
if(!(datas[num].attack())) {
// 다시 공격하겠습니까?(answer)
System.out.print("다시 공격하시겠습니까? (Y/N)");
answer = sc.next();
// Y면 다시 while문 처음의 attack 다시 실행
if(answer.equals("Y")) {
System.out.println("다시 공격을 시도합니다.");
}
// N 또는 그 외의 답이면 전투에서 벗어남
else {
System.out.println("무사히 도망쳤습니다.");
break;
}
}
// 성공했을 때
else {
break;
}
}
}
// 만약 menu가 2이면
else if(menu==2) {//전체상태 출력
if(isEmpty(cnt)) {//소유한 포켓몬이 없는지 유효성 검사
continue;
}
System.out.println("================");
for(int i=0;i<cnt;i++) {
System.out.println(datas[i].toString());
}
System.out.println("================");
}
else if(menu == 3) { // 3. 울음소리 듣기
// 보유한 포켓몬이 있는지 유효성 검사(isNull)
if(isEmpty(cnt)) {
continue;
}
//포켓몬 선택
int num;
num=pokemonMenu(cnt, datas); // 포켓몬 선택 메뉴 출력
// 울음소리 출력
System.out.print(datas[num].getName() + " : ");
datas[num].hello();
}
// 만약 menu가 4이면
else if(menu == 4) { // 포켓몬 잡기
// 포켓몬을 더 잡을 수 있는지 확인
if(isFull(cnt, datas)) { //만약 공간이 꽉 찼다면
System.out.println("더 이상 포켓몬을 잡을 수 없습니다!");
continue;
}
// 포켓몬 이름 배열
String[] pokemonName = {"메타몽", "조로아", "탕구리", "뚜벅쵸"};
// 잡을 수 있는 포켓몬 출력
System.out.println("잡을 수 있는 포켓몬");
// 포켓몬 이름 배열을 차례로 출력(for each문)
int i = 1; // 번호 출력용
for(String name : pokemonName) {
// 이름들 차례로 출력
System.out.println(i+". "+ name);
i++;
}
// 포켓몬을 선택 받음
System.out.print("잡을 포켓몬을 선택해주세요 >> ");
int num = getValidInput(1, 4);
// 포켓몬을 잡음
if(num == 1) { // 메타몽, 1이라면
// 메타몽 객체 생성
datas[cnt] = new Ditto();
System.out.println("메타몽을 잡았습니다!");
}
else if(num == 2) { // 조로아, 2라면
// 조로아 객체 생성
datas[cnt] = new Zorua();
System.out.println("조로아를 잡았습니다!");
}
else if(num == 3) { // 탕구리, 3이라면
// 탕구리 객체 생성
datas[cnt] = new Cubone();
System.out.println("탕구리를 잡았습니다!");
}
else if(num == 4) { // 뚜벅쵸, 4라면
// 뚜벅초 객체 생성
datas[cnt] = new Oddish();
System.out.println("뚜벅쵸를 잡았습니다!");
}
// 소지 포켓몬 추가
cnt++;
}
else { // 잘못 입력시
System.out.println("잘못 입력하셨습니다.");
}
}
}
}
< 수정 반영한 부분>
- selectOne() 함수 이름을 getValidInput() 으로 수정
- isNull() 보다는 isEmpty()가 올바르므로 이 함수또한 이름 수정
- 간단한 오탈자(뚜벅쵸 초 ...) 수정
- 메뉴에 문자열을 입력한 경우 NumberFormatException 오류가 발생는데, 이를 getValidInput()에서 try-catch 문을 이용하여 예외처리
- hello()와 attackVoice()는 자식클래스에서 오버라이딩하여 받아오고, 포켓몬 클래스에서는 abstract로 변경(오버라이딩 강제)
- 멤버변수 pulblic-> private , getter setter 받아옴
- levelUp()함수 void로 변경
- 그 외 부드럽지 않았던 부분 수정
'프로젝트' 카테고리의 다른 글
COMA 클라이밍 크루 최종 프로젝트 자료 (0) | 2024.11.14 |
---|---|
[팀 프로젝트] COMA 클라이밍 크루 커뮤니티 중간 프로젝트 후기 및 느낀점 (1) | 2024.10.01 |
[JAVA] 쇼핑몰 프로그램 MVC 패턴으로 구현하기 프로젝트 (0) | 2024.07.24 |
[JAVA] 포켓몬 게임 프로젝트 (2) | 2024.07.12 |
UP - DOWN 게임 만들기 (첫 번째 팀 프로젝트, 셀프 리뷰 ) (0) | 2024.07.01 |