본문 바로가기

JAVA

[java]OOP 게임 만들기

728x90
SMALL

1.MVC 패턴 구현 프로그램 작성

 1. 패키지 만들기

model - data

view - 입력,출력(사용자)

controller_로직

 

2.GAME Interface 작성

   * 인터페이스를 구현하는 클래스에서 공통적으로 구현해야 하는 기능 정의

   - 1. 메뉴 출력

   - 2. 캐릭터 생성

   - 3. 전투 모드

   - 4. 상대 캐릭터 생성

   - 5. 내 캐릭터 상태 확인

 

[controller 인터페이스 구현하기]

<GameInterface.java>

package com.smhrd.controller;

import com.smhrd.model.Charac; //ctrl+shift+o 하면 인폴트되면서 Charac 오류 사라짐


//게임을 만들기위한 틀
//1.게임 내에 구현해야하는 기능 정의 (로직 x)
//2.기능을 구현할 메서드의 이름 정의
public interface GameInterface {
	//인터페이스는 추상메서드, 상수만 정의가능
	public static final int a =10;
	int b =10; //자동으로 public static final 키워드가 작성됨

	//인터페이스 안에는 접근제한자를 public 만 작성 가능
	//메뉴출력, 캐릭터생성, 전투모드, 상대캐리터생성, 내캐릭터상태확인
	//1.메뉴 출력
	public abstract void printMenu();
	
	//2. 내 캐릭터 생성
	//1,2번 중에 사용자가 선택 -> 선택한 캐릭터를 생성하여 반환
	//생성될 캐릭터 -> 라이언, 춘식이
	public abstract Charac myCharac(int select);
	
	//3.상대방 캐릭터 생성
	//내캐릭터가 무서인지에 따라서 상대방 캘릭터는 다른 캐릭터로 결정
	//ex) 내캐릭터(춘식) -> 상대캐릭터(라이언)
	public abstract Charac oppCharac(Charac myCharac);
	
	//4. 전투모드
	//내캐릭터가 공격/방어 선택 ->죽은캐릭터가 있는 지 반환 -> 또 공격/방어 결정
	public abstract  boolean battle(Charac myC, Charac oppC, int ad);
	
	//인터페이스 안에서 메서드 선언(pubic abstract 키워드 작성이 기본 -> 안써도 됨)
	//5. 내 캐릭터 상태확인
	public abstract void checkMyC(Charac myC);
 }

3. 캐릭터 추상클래스 작성

    * 추상클래스를 상속받는 클래스에서 공통적으로 사용해야 하는 기능 정의

   - 1. 필드(타입, 레벨, 체력, 경험치, 공격력, 방어력)

   - 2. 메서드(캐릭터 정보 가져오기, 공격하기, 방어하기, 스킬사용하기, 캐릭터 아스키 아트 출력하기, 레벨업하기)

 

4. 캐릭터 클래스 작성(춘식/라이언)

타입: 춘식 타입: 라이언
레벨: 1 레벨: 1
체력: 20 체력: 20
경험치: 0 경험치:0
공격력: 9 공격력:10
방어력:7 방어력: 5
춘식이 아스키 출력하기 라이언 아스키 출력하기

<Charac.java>

package com.smhrd.model;

public abstract class Charac {
	//추상메서드가 하나라도 있으면 -> 추상클래스
	//추상메서드 없더라도 abstract 작성하면 -> 추상클래스
	//추상클래스로는 객체 생성 불가능
	
	//캐릭터들의 공통 속성
	private String type; //춘식/라이언
	private int level; //레벨
	private int hp; //체력
	private int xp; //경험치
	private int atk; //공격력
	private int def; //방어력
	
	//생성자: 객체 생성
	//추상클래스 -> 객체 생성 불가능
	//추상클래스 내에 생성자 작성은 가능(객체 생성x, 속성 초기화용 사용)
	//레벨, 체력, 경험치를 동일한 값을 가지게 초기화
	//타입, 공격력, 방어력 -> 사용자가 정의한 값으로 초기화
	public Charac(String type, int atk, int def) {
		this.type=type;
		//level,hp,xp 모든 캐릭터 동일
		this.level=1;
		this.hp = 50;
		this.xp =0;
		this.atk = atk;
		this.def =def;
	}	
	//캐릭터들의 공통 기능(메서드)
	//1. 캐릭터 속성(타입, 레벨, 체력...)확인/가지고 올 수 있는 메서드
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public int getLevel() {
		return level;
	}
	public void setLevel(int level) {
		this.level = level;
	}
	public int getHp() {
		return hp;
	}
	public void setHp(int hp) {
		this.hp = hp;
	}
	public int getXp() {
		return xp;
	}
	public void setXp(int xp) {
		this.xp = xp;
	}
	public int getAtk() {
		return atk;
	}
	public void setAtk(int atk) {
		this.atk = atk;
	}
	public int getDef() {
		return def;
	}
	public void setDef(int def) {
		this.def = def;
	}
	
	//2.공격
	//누구를 공격하는지 명시, 상대방에게 데미지를 입혀야 함
	public void attack(Charac oppC) {
		System.out.println(this.type+"이 "+oppC.getType()+"을 공격!");
		
		//내공격력이 상대방 방어력보다 낮으면 공격 불가능
		//공격: 상대방현재체력- 내공격력+상대방 방어력
		if(this.getAtk()>=oppC.getDef()) {
			oppC.setHp(oppC.getHp() - this.getAtk()+ oppC.getDef());
		}
	}
	
	//3.방어
	//내캐릭터가 방어할때 출력
	public void defence() {
		System.out.println(this.type+"가 방어!");
	}
	
	//4.스킬사용
	//내공격력에서 +5만큼 데미지 입힉
	public void skill(Charac oppC) {
	System.out.println(this.type+"이 "+oppC.getType()+"에게 스킬사용!");
		
		//내공격력이 상대방 방어력보다 낮으면 공격 불가능
		//공격: 상대방현재체력- 내공격력+상대방 방어력
		if(this.getAtk()>=oppC.getDef()) {
			oppC.setHp(oppC.getHp() - (this.getAtk()+5)+ oppC.getDef());
	}
  }
	
	//5.라벨업
	//경험치가 30보다 높아지면 레벨업
	//레벨+1, 경험치-30, 체력(꽉채워줌(50)), 공격력+5, 방어력+5
	public void levelUp(){
		System.out.println("레벨이 올랐습니다!");
		this.setLevel(this.getLevel()+1);
		//this.level+=1;
		this.setXp(this.getXp()-30);
		this.setHp(50);
		this.setAtk(this.getAtk()+5);
		this.setDef(this.getDef()+5);
	}
	
	//생성한 캐릭터의 아스키 아트 출력
	//캐릭터마다 출력되는 형태가 다르기 때문에
	//상속받은 클래스내에서 재정의
	public abstract void printASCII();
}

<Chunsik.java>

package com.smhrd.model;

public class Chunsik extends Charac{
	
	//타입,레벨,체력,경험치,공격력,방어력 초기화
	//레벨,체력,경험치 ->모든 캐릭터가 초기값이 동일 -> Charac 정의
	//타입(춘식), 공격력(9), 방어력(7)
	public Chunsik() {
		//상위클래스가 가지고 있는 속성 초기화
		// -> 상위클래스의 생성자를 호출
		
		//상위클래스(Charac)생성자를 호출,
		//지금 생성되는 춘식이의 객체의 타입, 공격력, 방어력을 초기화할 값을 보내줌!
		super("춘식이", 9 ,7);
	}

	@Override //Add unimplemented methods를 클릭하면 @override 가 추가된다
	public void printASCII() {
		System.out.println("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMMMMMMWKkkOOOOkkkkkkkOOOk0NMMMMM\r\n"
				+ "MMMMMMMMMMMMMM0ox0OkkkO0000OkkxkkddXMMMM\r\n"
				+ "MMMMMMMMMMMMNOok0K0000000000000000ddKMMM\r\n"
				+ "MMMMMMMMMMMNxdOKKKKK0KKKK0000000000xo0MM\r\n"
				+ "MMMMMMMNXWWxo0KKKKkddk0K000kx0000000xdKM\r\n"
				+ "MMMMMWOddxOoxK0KKKxcldkkkOOolOK00000OoOM\r\n"
				+ "MMMW0xdxkxclOK0KKKklcokOkkook00000000okM\r\n"
				+ "MMMOlkKxlxdckK0KK0kl:oxdxklck0000000OokM\r\n"
				+ "MMMklk0klxOld0KK00000kl:ldkO00000000doKM\r\n"
				+ "MMMNOkxclOKkldOK0K00K0xdk000000000Odo0MM\r\n"
				+ "MMMMMMW0ocll:;:llodO000O0000000OxolxXMMM\r\n"
				+ "MMMWXKko:;;:::::;;;:ccodddddddddddodXMMM\r\n"
				+ "WKxlc:;::::::::::::::;:oxxxkkOO000OodNMM\r\n"
				+ "Kc,:::::;,,;;:::::::::;cx00kookOOO0dl0MM\r\n"
				+ "Kc,::::;',;;::::::::;;;;lOxcokOOOOOooXMM\r\n"
				+ "WKdlc::,';:;::::;;:;;;:;cxl:xOOkxdod0MMM\r\n"
				+ "MMMWNXK0d:;,,,,,,,,;;;::ldxdxxxxxk0NMMMM\r\n"
				+ "MMMMMMMMMN0OkkkkkO000KXNWMMMMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM");
		
	}

}

<Ryan.java>

package com.smhrd.model;

public class Ryan extends Charac {

	public Ryan() {
		super("라이언", 10, 5);
	}

	@Override
	public void printASCII() {
		System.out.println("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMMMMMMWNXNWWMMMMMMMMMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMMMMMW0kO0KXNWWMMMMMMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMMWXOkdxkO0KKKXXNNWWMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMWKdclodxkO0KKKKKXXXXXNWMMMMMMMMM\r\n"
				+ "MMMMMMMWOc;codxkkolloox0XXXXXXNWMMMMMMMM\r\n"
				+ "MMMMMMM0c,;cldxkOOoloodOXXXK0KXNMMMMMMMM\r\n"
				+ "MMMMMMNd,,;cloxkOkook0KKKXXOdod0WMMMMMMM\r\n"
				+ "MMMMMMKl,,;:lodxkO000KXOdkKKxod0WMMMMMMM\r\n"
				+ "MMMMMMXl,;;::loxxOkxx0WKoxXKkk0XWMMMMMMM\r\n"
				+ "MMMMMMWk:;;;::lodxdoldO0KNXK000NMMMMMMMM\r\n"
				+ "MMMMMMMNkc;;::cclooooddddkOOOOXWMMMMMMMM\r\n"
				+ "MMMMMMMMWKxl;;:clllooooddxxxOXWMMMMMMMMM\r\n"
				+ "MMMMMMMMMMWk;;okOkdlllllodkKNMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMMXl,:x0KKOkxkO000XWMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMWk;,cx0K0000OkOkOKNMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMNo,,:dO0000K0kxdx0NMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMNkdddk0XXKKXXKKKKNWMMMMMMMMMMMM\r\n"
				+ "MMMMMMMMMMMMMMWWMWWWWMMMMMMMMMMMMMMMMMMM");
		
	}

}

<Test.java>

package com.smhrd.view;

import com.smhrd.model.Charac;
import com.smhrd.model.Chunsik;
import com.smhrd.model.Ryan;

public class Test {

	public static void main(String[] args) {
		
		//배열/arrayList안에 춘식, 라이언을 같이 넣을 수 있다
		//배열/arraylist 기본적으로 같은 타입만 넣을 수 있어요
		
		int[]arr = new int[10]; //정수형만 들어갈 수 있음
		Chunsik[]css=new Chunsik[4];
		
		//춘식(캐릭터 상속받음 ) ->캐릭터 타입을 바꿀수 있음(업캐스팅)
		Chunsik cs = new Chunsik();
		cs.printASCII();
		
		//라이언(캐릭터 상속받음) -> 캐릭터 타입으로 바꿀수있음(업케스팅)
		Ryan r = new Ryan();
		r.printASCII();
		
		Charac[] cr = new Charac[2];  //Object[]cr = new Object[2];
		//업캐스팅은 자동형변환(따로 지정하지 않아도 됨)
		cr[0]=cs;
		cr[1]=r;
		
		cr[0].printASCII();
		//Chunsik c = (Chunsik)cr[0];
		//c.printASCII();
		
		
		
		//추상클래스 절대 객체 생성 불가능 -> 컴파일오류
		//new Charac("a",20,20);

	}

}

<GameMain>

package com.smhrd.view;

import java.util.Scanner;

import com.smhrd.controller.GameController;
import com.smhrd.model.Charac;

public class GameMain {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);

		// msin 실행되게 되면은
		// 사용자가 메뉴(캐릭터 생성, 전투, 내캐릭터 확인, 종료)를 선택할 수 있게 함
		// ->controller - prinMenu()
		// 1.GameController 객체 생성 후 참조값 저장하고있는 레퍼런스 변수 선언
		GameController gc = new GameController();
		// 메뉴가 반복적으로 출력 -> 사용자는 1~4 숫자 입력
		// 1 -> 내 캐릭터 생성! 2-> 전투모드! 3->내 캐릭터 확인! 4 ->반복문 종료

		// 내캐랙터(라이언/춘식)저장 공간
		Charac myC = null;

		while (true) {
			gc.printMenu();
			int menu = sc.nextInt(); // 1~4

			if (menu == 1) {
				System.out.println("내 캐릭터 생성!");

				if (myC == null) {
					System.out.println("[1]라이언 [2]춘식이");
					int select = sc.nextInt();

					myC = gc.myCharac(select);// 캐릭터생성

					gc.checkMyC(myC);
				}else {
					System.out.println("이미 생성된 캐릭터가 있습니다!");
				}
				// 1. 캐릭터는 딱 1개만 생성할 수 있음!
				// 만약, 캐릭터가 생성된 상태라면 "이미 생성된 캐릭터가 있습니다!" 출력

				// 캐릭터가 생성되지 않았을 때
				// [1]라이언 [2]춘식이 선택하게 함

				// Controller - myCharac 캐릭터 생성

				// 생성된 캐릭터의 타입만 출력
				// ckeckMyC -> 전체 속성 출력

			} else if (menu == 2) {
				System.out.println("전투모드!");
				if(myC==null) {
					System.out.println("캐릭터를 생성하세요!");
				}else {//캐릭터가 생성되어 있는 경우
					//1. 상대방 캐릭터 생성
					//내 캐릭터(춘식) -상대방(라이언), 내 캐릭터(라이언)-상대방(춘식)
					Charac oppC = gc.oppCharac(myC);
					
					while(true) {
						System.out.println("[1]공격 [2]방어");
						int ad = sc.nextInt();
						
						//       (내캐릭터, 상대방캐릭터, 공격/방어)
						boolean cont = gc.battle(myC, oppC, ad);
						//cont가 true 이면 계속 전투
						//cont가 false이면 전투 중단 -> 반복문 중단
						if(!cont) {
							System.out.println("전투중단");
							break;
						}
					}
				}
				
				
				
				
				
			} else if (menu == 3) {
				System.out.println("내 캐릭터 확인!");
				if(myC!=null) {//캐릭터가 생성되어있을 때에만
					gc.checkMyC(myC);
				}
				
			} else {// 4
				System.out.println("게임 종료!");
				break;
			}
		}

	}

}

<GameController>

package com.smhrd.controller;

import com.smhrd.model.Charac;
import com.smhrd.model.Chunsik;
import com.smhrd.model.Ryan;

public class GameController implements GameInterface {

	// GameController 아래 빨간줄 떳을때 add unimplemented methods 누르면 아래 생성
	@Override
	public void printMenu() {
		System.out.print("[1]내 캐릭터 생성 [2]전투모드 [3]내 캐릭터 확인 [4]종료 ");
	}

	// 내 캐릭터 생성
	@Override
	public Charac myCharac(int select) {

		// 1번 선택 ->라이언 객체 생성
		// 2번 선택 -> 춘식 객체 생성
		// 생성된 캐릭터 반환
		Charac myC = null; // 라이언/춘식 생성된 객체 담을 용도
		if (select == 1) {
			// 라이언 객체 생성
			myC = new Ryan(); // 업캐스팅(자동형변환)
		} else if (select == 2) {
			// 춘식 객체 생성
			myC = new Chunsik(); // 업캐스팅(자동형변환)
		}
		// 생성된 캐릭터의 아스키아트 출력
		myC.printASCII();
		// 생성된 객체 반환
		return myC;
	}

	@Override
	public Charac oppCharac(Charac myCharac) {
		// 내 캐릭터 어떤 타입인지
		// myCharac가 원래 라이언 타입 이었니?
		// 원래 라이언 -> true
		// 원래 라이언타입이 아니었다 -> false

		Charac opp = null;

		if (myCharac instanceof Ryan) {
			// 춘식이 생성
			opp = new Chunsik();
			System.out.println("야생의 춘식이가 나왔습니다!");
		} else if (myCharac instanceof Chunsik) {
			// 라이언 생성
			opp = new Ryan();
			System.out.println("야생의 라이언이 나왔습니다!");
		}

		return opp;
	}

	// 한번의 공격 - 방어
	// 한캐릭터라도 죽은 경우에는 -> flase
	// 계속 전투를 할 수 있는 경우(아무도 죽지 않은 경우)에는 ->true
	@Override
	public boolean battle(Charac myC, Charac oppC, int ad) {
		// 1. 사용자가1 -> 공격
		// 내캐릭터는 상대방 공격, 상대방은 방어
		// 2. 사용자가 2 -> 방어
		// 상대방은 내캐릭터를 공격, 내 캐릭터는 방어

		// 내캐릭터의 체력(hp)와 상대방캐릭터의 체력(hp)을 출력

		if (ad == 1) {// 내캐릭터가 공격
			myC.attack(oppC);
			oppC.defence();
		} else if (ad == 2) {
			myC.defence();
			oppC.attack(myC);
		}

		System.out.println("내캐릭터 HP : " + myC.getHp());
		System.out.println("상대캐릭터 HP : " + oppC.getHp());

		//1. 내캐릭터가 죽었는지(myC HP <=0)
		//내캐릭터의 경험치 -10 감소
		//전투종료
		
		//2. 상대방캐릭터가 죽었는지(oppC HP <=0)
		//내캐릭터의 경험치를 +10증가
		//만약에 경험치를 10 증가시킨후 내 경험치가 30이상이 되면은
		//    ->레벨1증가
		boolean cont = true; //전투를 계속 할 수 있는지 없는지
		if(myC.getHp()<=0) {
			if(myC.getXp()>=10) {
				myC.setXp(myC.getXp()-10);
			}else {//경험치가 10보다 작을 때는 무조건 0으로 수정
				myC.setXp(0);
			}
			System.out.println(myC.getType()+"이 죽었습니다!");
			cont = false;
		}else if(oppC.getHp()<=0) {
			myC.setXp(myC.getXp()+10);
			
			if(myC.getXp()>=30) {
				myC.levelUp();
			}
			System.out.println(oppC.getType()+"이 죽었습니다!");
			cont = false;
		}
		
		
		//캐릭터중 하나라도 죽은 캐릭터가 있으면 false 반환
		//죽은 캐릭터가 없으면 true반환
		return cont;
	}

	// 내캐릭터 현재 상태 출력
	// 타입, hp,xp,atk...
	@Override
	public void checkMyC(Charac myC) {
		System.out.println("내 캐릭터 타입 : " + myC.getType());
		System.out.println("내 캐릭터 레벨 : " + myC.getLevel());
		System.out.println("내 캐릭터 HP : " + myC.getHp());
		System.out.println("내 캐릭터 XP : " + myC.getXp());
		System.out.println("내 캐릭터 공격력 : " + myC.getAtk());
		System.out.println("내 캐릭터 방어력 : " + myC.getDef());

	}

}
728x90
LIST

'JAVA' 카테고리의 다른 글

반복문(for문) 예제  (0) 2022.09.04
JDBC응용  (0) 2022.09.01
[Java] 자료구조(선형구조와 비선형구조)  (0) 2022.08.28
[Java] 상속의 개념과 코드 예제  (0) 2022.08.27
[JAVA] 객체, 클래스,인스턴스의 차이 및 예시  (0) 2022.08.27