GameMain.java
package chapter11.interface_part;
import java.util.Scanner;
public class GameMain {
public static void main(String[] args) {
/*
* seoul45_game
* 1. 프로그램이 실행되면 메뉴를 출력한다.
* 2. 메뉴는 (1.캐릭터 생성, 2.캐릭터 정보, 3.전직하기, 4.공격하기, 0.종료)
* - (1.캐릭터 생성)을 선택한 경우, 이름과 스탯값을 초기값으로 하는 Novice(평민)클래스형 인스턴스를 생성한다.
* 스탯은 (힘, 민첩, 지능)이 있으며 각각 랜덤한 값을 가지고,
* 형평성을 위해 스탯의 총 합이 15이상인 경우에만 저장되도록 하며,
* 사용자의 선택에 따라 해당 스탯을 저장 or 스탯 재부여 할 수 있도록 한다.
* 3. - (2.캐릭터 정보)를 선택한 경우, 생성된 캐릭터의 이름, 직업, 힘, 민첩, 지능을 출력한다.
* 4. - (3.전직하기)를 선택한 경우, 생성된 캐릭터의 정보를 초기값으로 가지는
* 선택한 클래스에 해당하는 인스턴스를 생성하고 문구를 출력한다.
* 5. - (4.공격하기)를 선택한 경우, Attack()메서드를 호출하여 직업(인스턴스)에 따라 공격한다.
* 6. - (5.스킬사용)을 선택한 경우, Skill()메서드를 호출하여 직업(인스턴스)에 따라 스킬을 사용한다.
* 7. - (0.종료)를 선택한 경우, 프로그램을 종료한다.
* 8. - 종료를 선택하기 전까지 반복한다.
* */
Scanner scan = new Scanner(System.in);
GameMain_Method gm = new GameMain_Method(); //1.GameMain는 GameMain_Method에 의존하고 있음(의존관계)
Novice character = null;
Skill skill = null;
int num = 0;
while(true) {
gm.printMenu(); //2.의존관계로 GameMain_Method의 매서드 호출
num = scan.nextInt();
switch (num) {
case 1 -> character = gm.createCharacter(); //호출한 값을 Novice 타입 맴버변수에 넣음
case 2 -> {
if(character != null) gm.characterInfo(character); //case 1에서 저장한 값을 담은 변수 character 를 매개변수로 메서드 호출
else gm.printText(3); //맴버변수 3을 가지고 메서드를 호출해라
}
case 3 -> {
if(character != null) {
int jobNum = gm.numberInput();
character = gm.jobSelect(jobNum, character);
} else gm.printText(3);
}
case 4 -> {
if(character != null) character.attack(); //예를들어 기사로 전직했다면 인스턴스는 기사, 타입은 Novice 이라 부모에게 먼ㅌ저 접근, 그러나 오버라이드 된 메서드가 우선권을 가지게 되어 기사 메서드가 호출됨
else gm.printText(3);
}
case 5 -> {
if(character != null) {
//character.skill(); 질문3.왜 case 4번과 다르게?
skill = gm.skill(character);
if(skill != null) skill.skill();
else gm.printText(4);
}
else gm.printText(3);
}
case 0 -> {
gm.printText(1);
return; //질문4. 무슨역할?
}
default -> gm.printText(2);
}
}
}
}
GameMain_Method.java
package chapter10.interface_part;
import java.util.Random;
import java.util.Scanner;
public class GameMain_Method {
public void printMenu() {
System.out.println();
System.out.println("""
=== ABCDE_rpg ===
1. 캐릭터 생성
2. 캐릭터 정보
3. 전직하기
4. 기본 공격
5. 스킬 사용
0. 종료
=================""");
System.out.print("번호를 선택하세요 : ");
}
//출력 문구만 모아 놓은 메서드
public void printText(int num) {
switch (num) {
case 1 -> System.out.println("게임을 종료합니다.");
case 2 -> System.out.println("번호를 잘못 입력하셨습니다.");
case 3 -> System.out.println("캐릭터를 생성하세요.");
case 4 -> System.out.println("스킬을 배우지 않았습니다.");
}
}
//캐릭터를 생성하는 메서드
//스탯 힘, 민첩, 지능을 랜덤한 숫자로 스탯의 총 합이 15이상일 경우에만 부여한다.
//사용자의 선택에 따라 저장 or 스탯 재부여 한다.
public Novice createCharacter() {
Scanner scan = new Scanner(System.in);
Random ran = new Random(); //난수를 생성할 도구 만듬(실제로 생성 x)
System.out.println("캐릭터를 생성합니다.");
System.out.print("사용하실 아이디를 입력해 주세요 : ");
String id = scan.next();
int str = 0, dex = 0, intel = 0, sum = 0; //지역변수
String text = "";
while(true) {
System.out.println("스탯을 부여합니다. ");
while(true) {
str = ran.nextInt(10);
dex = ran.nextInt(10);
intel = ran.nextInt(10);
sum = str + dex + intel;
//스탯의 총 합이 15이상일 때까지 각 스탯에 랜덤한 숫자 부여
if(sum >= 15)
break; //15이상이면 가까운 while문 탈출 //아닐경우 다시 반복문으로 돌아가 난수 발생
}
System.out.printf("부여된 스탯정보: 힘[%d], 민첩[%d], 지능[%d]\n", str, dex, intel);
System.out.print("스탯을 다시 받으시겠습니까? (y/n) : ");
text = scan.next();
if(text.equals("n")) //문자와 비교하기 위해 equals 사용
break; //대답이 n일 경우 : while문 탈출 (드래그 하면 무슨 반복문에 걸려있는지 확인 가능)
//대답이 n가 아닐경우 : break가 없어서 다시 반복문으로 돌아가 난수 발생시킴 (true 무한 반복)
}
//질문1.클래스에 직접 대입x, 동일 클래스 타입에(빈깡통, 지역변수) 설정된 값을 저장함
//질문2.인스턴스 생성후 생성자로 값 설정해주고 이 인스턴스의 참조값을 담음
Novice novice = new Novice(id, str, dex, intel);
System.out.println(novice); //저장된 값을 프린트 , toString
System.out.println("현재 정보로 저장합니다.");
return novice; //호출한 곳으로 저장한 값을 보냄
}
//직업에 따라 인스턴스를 생성하는 메서드
//선택한 직업에 따라 해당 클래스로 인스턴스를 생성하고, 문구를 출력한다.
public Novice jobSelect(int num, Novice novice) {
Novice character = null;
switch (num) {
case 1 -> {
character = new Knight(novice.getName(), novice.getStrength(),
novice.getDexterity(), novice.getIntelligence());
System.out.println("기사로 전직합니다.");
}
case 2 -> {
character = new Thief(novice.getName(), novice.getStrength(),
novice.getDexterity(), novice.getIntelligence());
System.out.println("도적으로 전직합니다.");
}
case 3 -> {
character = new Magician(novice.getName(), novice.getStrength(),
novice.getDexterity(), novice.getIntelligence());
System.out.println("마법사로 전직합니다.");
}
}
return character;
}
//전직을 위해 번호를 입력받는 메서드
public int numberInput() {
Scanner scan = new Scanner(System.in);
int num = 0;
while(num > 3 || num < 1) {
System.out.println("""
=== 직업 종류 ===
1. 기사
2. 도적
3. 마법사""");
System.out.print("전직할 직업의 번호를 선택하세요 : ");
num = scan.nextInt();
}
return num;
}
//생성된 캐릭터의 정보를 보여 주는 메서드
//생성된 인스턴스에 따라 직업표시가 달라진다.
public void characterInfo(Novice novice) { //생성된 character 정보받음 타입이 Novice 이니까 여기서도 Novice 타입으로받음
String job = "";
if(novice instanceof Knight) //만약 기사로 전직했다면 jobSelect메서드에서 기사 인스턴스를 생성하여 character에 저장했을거라 본인과 본인을 비교하게 됨
job = "기사";
else if(novice instanceof Thief)
job = "도적";
else if(novice instanceof Magician)
job = "마법사";
else
job = "평민"; //위에 셋다 아니라면 job 을 평민으로 설정
String str = String.format("[ID: %s(%s), stat: 힘(%d), 민첩(%d), 지능(%d)]"
, novice.getName(), job, novice.getStrength() // privater 변수라 get사용
, novice.getDexterity(), novice.getIntelligence());
System.out.println(str);
}
public Skill skill(Novice novice) {
Skill skill = null;
if (novice instanceof Knight knight)
skill = knight;
else if (novice instanceof Thief thief)
skill = thief;
else if (novice instanceof Magician magician)
skill = magician;
return skill;
}
}
평민
package chapter10.interface_part;
//평민
public class Novice {
//멤버 변수
private String name; //캐릭터 이름
private int strength; //힘 스탯
private int dexterity; //민첩 스탯
private int intelligence; //지능 스탯
//기본생성자
public Novice() {}
//명시적 생성자
public Novice(String name, int strength, int dexterity, int intelligence) {
this.name = name;
this.strength = strength;
this.dexterity = dexterity;
this.intelligence = intelligence;
}
//멤버 메서드
public void attack() {
System.err.println("기본 공격");
}
//getter / setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStrength() {
return strength;
}
public void setStrength(int strength) {
this.strength = strength;
}
public int getDexterity() {
return dexterity;
}
public void setDexterity(int dexterity) {
this.dexterity = dexterity;
}
public int getIntelligence() {
return intelligence;
}
public void setIntelligence(int intelligence) {
this.intelligence = intelligence;
}
//객체 정보 출력용 Object의 멤버 메서드 재정의(오버라이드)
@Override
public String toString() {
return String.format("[ID: %s, stat: 힘(%d), 민첩(%d), 지능(%d)]"
, name, strength, dexterity, intelligence);
}
}
나이트
package chapter10.interface_part;
//기사
public class Knight extends Novice implements Skill{
//명시적 생성자
//Knight형 인스턴스 생성시 Novice의 명시적 생성자를 호출하여 각각의 초기값을 가지는 인스턴스 생성
public Knight(String name, int strength, int dexterity, int intelligence) {
super(name, strength, dexterity, intelligence);
}
//상위 클래스 Novice의 attack()메서드를 재정의(오버라이드)
@Override
public void attack() {
System.err.println("강력한 배쉬 공격");
}
//interface Skill의 메서드 skill()를 구현한다. (오버라이드)
@Override
public void skill() {
System.err.println("쇼크 스턴");
}
}
도적
//도적
public class Thief extends Novice implements Skill{
//명시적 생성자
//Thief형 인스턴스 생성시 Novice의 명시적 생성자를 호출하여 각각의 초기값을 가지는 인스턴스 생성
public Thief(String name, int strength, int dexterity, int intelligence) {
super(name, strength, dexterity, intelligence);
}
//상위 클래스 Novice의 attack()메서드를 재정의(오버라이드)
@Override
public void attack() {
System.err.println("치명적인 공격");
}
//interface Skill의 메서드 skill()를 구현한다. (오버라이드)
@Override
public void skill() {
System.err.println("중독");
}
}
마법사
package chapter10.interface_part;
//마법사
public class Magician extends Novice implements Skill{
//명시적 생성자
//Magician형 인스턴스 생성시 Novice의 명시적 생성자를 호출하여 각각의 초기값을 가지는 인스턴스 생성
public Magician(String name, int strength, int dexterity, int intelligence) {
super(name, strength, dexterity, intelligence);
}
//상위 클래스 Novice의 attack()메서드를 재정의(오버라이드)
@Override
public void attack() {
System.err.println("매직 애로우 공격");
}
//interface Skill의 메서드 skill()를 구현한다. (오버라이드)
@Override
public void skill() {
System.err.println("메테오");
}
}
스킬
package chapter10.interface_part;
public interface Skill {
//스킬메서드
public void skill();
}