필수 기능
- Player라는 기본 클래스를 정의 합니다.
- Player 클래스에는 attack()이라는 순수 가상 함수를 포함합니다.
- attack() 함수는 무기를 휘두르기만 하는 기본적인 공격 함수입니다.
- Player 클래스에는 attack()이라는 순수 가상 함수를 포함합니다.
- Player 클래스를 상속받아 다양한 직업 클래스를 생성합니다.
- 예) Warrior, Magician, Thief, Archer
- 각 직업 클래스에서 attack()함수를 재정의(오버라이딩)하여 해당 직업의 공격을 출력하면 됩니다!
- 예) Warrior, Magician, Thief, Archer
- 메인 함수에서 Player 타입의 포인터 배열을 선언하고, 해당하는 번호를 입력하면 (1. 전사 2. 마법사 3. 도적 4. 궁수) Warrior, Magician, Thief, Archer를 각각 배열의 원소로 선언합니다. → 이후 Player는 attack() 함수를 호출하여 공격합니다.
- 전체적인 구조는 아래와 같습니다.
도전 기능
필수 기능 가이드에 있는 요구사항을 만족하는 코드를 구현했다면, 아래 코드스니펫을 보고 요구사항대로 Monster클래스를 정의해주세요!
class Monster {
public:
// Monster 생성자
// - 몬스터의 이름을 매개변수로 입력 받습니다.
// - 모든 몬스터는 HP 10, 공격력 30, 방어력 10, 스피드 10의 능력치를 가집니다.
Monster(string name);
// 몬스터의 공격 함수
// - 플레이어 객체의 포인터를 매개변수로 입력 받습니다.
// - 몬스터의 공격력-플레이어의 방어력을 데미지로 정의합니다.
// - 만약 위에서 계산한 데미지가 0 이하라면, 데미지를 1로 정의합니다.
// - 플레이어에게 얼마나 데미지를 입혔는지 출력합니다.
// - setHP 함수를 실행하여 HP-데미지 계산 결과를 매개변수로 전달합니다.
// - setHP에서 리턴 받은 생존 여부를 기준으로 분기문이 실행됩니다.
// - 생존했을 경우, 플레이어의 남은 HP만 출력합니다.
// - 생존하지 못했을 경우, 플레이어의 남은 HP와 몬스터의 승리 문구를 출력합니다.
void attack(Player* player);
// 몬스터의 속성값을 리턴하는 get 함수
string getName();
int getHP();
int getPower();
int getDefence();
int getSpeed();
// 몬스터의 속성값을 정의하는 set 함수
// setHP의 경우 배틀 시스템에 직결되는 함수이므로, 생존 여부를 리턴합니다.
// HP가 1 이상일 때 true, HP가 0 이하가 되었을 때 false를 리턴합니다.
// HP가 1 이상일 때만 새로운 HP값 정의를 진행합니다.
// 0 이하일 경우 HP를 0으로 정의합니다.
void setName(string name);
bool setHP(int HP);
void setPower(int power);
void setDefence(int defence);
void setSpeed(int speed);
protected:
string name; // 몬스터의 이름
int HP; // 몬스터의 HP
int power; // 몬스터의 공격력
int defence; // 몬스터의 방어력
int speed; // 몬스터의 스피드
};
Player의 attack() 함수를 오버로딩하여 attack(Monster* monster) 함수를 구현하세요.
자세한 사항은 아래 코드 스니펫을 참조하시면 됩니다!
class Monster;
class Player {
public:
Player(string nickname);
virtual void attack() = 0;
virtual void attack(Monster* monster) = 0;
void printPlayerStatus();
// getter
// ...
// setter(setHP, setMP는 리턴 타입 bool로 설정)
// ...
protected:
// attributes
};
void JobName::attack(Monster* monster) {
// 플레이어의 공격력-몬스터의 방어력을 계산하여 데미지로 정의합니다.
// 계산된 데미지가 0 이하일 경우, 데미지를 1로 정의합니다.
// 공격 문장을 출력합니다.
// - 전사, 마법사: 계산된 데미지로 1회 공격
// - 궁수: 계산된 데미지/3으로 3회 공격 (소수점 생략)
// - 도적: 계산된 데미지/5으로 5회 공격 (소수점 생략)
// - 궁수와 도적의 경우, 3과 5로 나눈 결과가 0이라면 1로 정의합니다.
// ex) * 슬라임에게 화살로 3의 피해를 입혔다! 3번 출력
// setHP를 호출하여 몬스터의 HP-데미지를 계산한 값을 매개변수로 전달합니다.
// 리턴된 생존 여부를 기준으로 분기문이 실행됩니다.
// 생존했을 경우 몬스터의 남은 HP 출력
// 생존하지 못했을 경우 몬스터의 남은 HP와 플레이어의 승리 문구 출력
}
필수 기능
Player
// Player.h
#pragma once
#include <iostream>
#include <string>
class Player
{
protected:
//필요한 캐릭터의 속성들을 변수 선언한다.
std::string job_name;
std::string nickname;
int Level;
int HP;
int MP;
int Power;
int Defence;
int Accuracy;
int Speed;
public:
virtual void initStats() = 0; // 직업별 초기 스탯을 위한 순수 가상 함수
virtual void attack() = 0; // 직업별 공격을 위한 순수 가상 함수
void printPlayerStatus();
void setjob_name(std::string job);
void setnickname(std::string name);
void setHP(int hp);
void setMP(int mp);
void setpower(int power);
void setdefence(int defence);
void setaccuracy(int accuracy);
void setspeed(int speed);
void setlevel(int level);
};
// Player.cpp
#include "Player.h"
using namespace std;
void Player::printPlayerStatus()
{
cout << "------------------------------------" << endl;
cout << "* 현재 능력치" << endl;
cout << "닉네임: " << nickname << endl;
cout << "직업: " << job_name << endl;
cout << "Lv. " << Level << endl;
cout << "HP: " << HP << endl;
cout << "MP: " << MP << endl;
cout << "공격력: " << Power << endl;
cout << "방어력: " << Defence << endl;
cout << "정확도: " << Accuracy << endl;
cout << "속도: " << Speed << endl;
cout << "------------------------------------" << endl;
}
void Player::setjob_name(string job)
{
job_name = job;
}
void Player::setnickname(string name)
{
nickname = name;
}
void Player::setHP(int hp)
{
HP = hp;
}
void Player::setMP(int mp)
{
MP = mp;
}
void Player::setpower(int power)
{
Power = power;
}
void Player::setdefence(int defence)
{
Defence = defence;
}
void Player::setaccuracy(int accuracy)
{
Accuracy = accuracy;
}
void Player::setspeed(int speed)
{
Speed = speed;
}
void Player::setlevel(int level)
{
Level = level;
}
Warrior, Archer, Magician, Thief
//Warrior.h
#pragma once
#include "Player.h"
class Warrior:public Player
{
public:
virtual void attack() override;
virtual void initStats() override;
};
//Warrior.cpp
#include "Warrior.h"
using namespace std;
void Warrior::initStats() // 직업별 초기 스탯 설정
{
setjob_name("전사");
setlevel(1);
setnickname(nickname); // nickname은 main에서 입력받음
setHP(300);
setMP(50);
setpower(70);
setdefence(50);
setaccuracy(60);
setspeed(50);
}
void Warrior::attack()
{
cout << "Slash attack!";
}
Archer, Magician, Thief의 헤더파일에 클래스명만 다르게했음.
소스파일에서는 초기 스탯을 다 다르게 설정하고 attack함수의 출력 메세지만 변경함.
main
//main.cpp
#include "Player.h"
#include "Warrior.h"
#include "Magician.h"
#include "Thief.h"
#include "Archer.h"
using namespace std;
// 메인 함수
int main()
{
Warrior wa;
Archer ar;
Magician ma;
Thief th;
Player* player[4] = {&wa, &ar, &ma, &th}; // Player 타입의 포인터 배열 선언
Player* job = nullptr;
int job_choice;
string name;
cout << "이름을 입력하세요." << endl;
cin >> name;
cout << "1.전사 2.궁수 3.마법사 4.도적" << endl << "직업 선택: ";
cin >> job_choice;
if (job_choice >= 1 && job_choice <= 4)
{
job = player[job_choice - 1];
}
else
{
cout << "잘못된 입력입니다.";
return 0;
}
if (job != nullptr)
{
job->setnickname(name); // nickname에 입력한 name값 넣어주기
job->initStats(); // 직업이 정해졌으니 초기 스탯 넣어주기
job->printPlayerStatus(); // 현재 직업 상태 메세지 출력
job->attack();
}
}
결과
도전 기능
필수 기능에서 작성했던 코드들을 도전 기능을 작성하다보니 좀 많이 수정이 됐다.(10시간 걸렸음..)
Player
// Player.h
#pragma once
#include <iostream>
#include <string>
class Player
{
protected:
std::string job_name;
std::string nickname;
int Level;
int HP;
int MP;
int Power;
int Defence;
int Accuracy;
int Speed;
int Damage; // 데미지 추가됨
public:
virtual void initStats() {}; // 순수 가상 함수에서 가상 함수로 수정했음.
virtual void attack() = 0;
virtual void givedamage(Player* player) {}; // damage를 주기 위한 매개변수 있는 가상 함수 선언
//게터 함수들이 추가됨.
int getpower();
int getdefence();
int getHP();
int getdamage();
std::string getname();
virtual void printPlayerStatus();
virtual void setjob_name(std::string job);
virtual void setnickname(std::string name);
virtual bool setHP(int hp); // setHP함수가 요구사항에서 bool로 하라해서 변경함
virtual void setHP2(int hp); // 원래 setHP의 기능이 setHP2로 이름만 바꿈
virtual void setMP(int mp);
virtual void setpower(int power);
virtual void setdefence(int defence);
virtual void setaccuracy(int accuracy);
virtual void setspeed(int speed);
virtual void setlevel(int level);
};
Player.h의 특이점은 initStats가 원래 순수 가상 함수였는데 현재 직업, 몬스터 클래스가 Player를 상속받는 클래스다 보니 하나라도 initStats를 구현하지 않으면 빌드 오류가 발생 하여 일반 가상 함수로 변경했음.
// Player.cpp
#include "Player.h"
using namespace std;
void Player::printPlayerStatus()
{
cout << "------------------------------------" << endl;
cout << "* 현재 능력치" << endl;
cout << "닉네임: " << nickname << endl;
cout << "직업: " << job_name << endl;
cout << "Lv. " << Level << endl;
cout << "HP: " << HP << endl;
cout << "MP: " << MP << endl;
cout << "공격력: " << Power << endl;
cout << "방어력: " << Defence << endl;
cout << "정확도: " << Accuracy << endl;
cout << "속도: " << Speed << endl;
cout << "------------------------------------" << endl;
}
void Player::setjob_name(string job)
{
job_name = job;
}
void Player::setnickname(string name)
{
nickname = name;
}
bool Player::setHP(int hp) // setHP 함수가 bool로 변경
{
return hp > 0;
}
void Player::setMP(int mp)
{
MP = mp;
}
void Player::setpower(int power)
{
Power = power;
}
void Player::setdefence(int defence)
{
Defence = defence;
}
void Player::setaccuracy(int accuracy)
{
Accuracy = accuracy;
}
void Player::setspeed(int speed)
{
Speed = speed;
}
void Player::setlevel(int level)
{
Level = level;
}
// 아래부터 도전 기능에서 추가됨.
int Player::getdefence()
{
return Defence;
}
int Player::getpower()
{
return Power;
}
int Player::getHP()
{
return HP;
}
void Player::setHP2(int hp)
{
HP = hp;
}
int Player::getdamage()
{
return Damage;
}
string Player::getname()
{
return nickname;
}
Player.cpp에서는 게터 함수가 좀 추가되고 setHP가 bool로 변하고 setHP2에 원래 setHP의 기능을 똑같이 구현했다.
각 직업(Warrior, Archer, Magician, Thief)
// Warrior.h
#pragma once
#include "Player.h"
class Warrior:public Player
{
public:
virtual void attack() override; // Player의 attack 함수를 재정의
virtual void initStats() override; // Player의 initStats 함수를 재정의
virtual void givedamage(Player* player) override;
};
각 직업의 헤더파일은 클래스 명만 다르고 다른건 다 똑같다.
// Warrior.cpp
#include "Warrior.h"
using namespace std;
void Warrior::initStats()
{
setjob_name("전사");
setlevel(1);
setnickname(nickname);
setHP2(50);
setMP(50);
setpower(50);
setdefence(20);
setaccuracy(5);
setspeed(5);
}
void Warrior::attack()
{
cout << "Slash attack!" << endl;
cout << getdamage() << "의 피해를 주었다." << endl;
}
void Warrior::givedamage(Player* player)
{ // 플레이어의 Power에서 몬스터의 defence를 빼서 Damage에 값을 대입함.
Damage = Power - player->getdefence();
if (Damage <= 0) // 만약 Damage가 0이하라면 1로 설정함.
{
Damage = 1;
}
}
소스파일은 전사, 마법사는 거의 비슷하지만 궁수, 도적은 공격 횟수를 추가하여 다르게 구현했다.
// Archer.cpp
#include "Archer.h"
using namespace std;
void Archer::initStats()
{
setjob_name("궁수");
setlevel(1);
setnickname(nickname);
setHP2(100);
setMP(80);
setpower(45);
setdefence(5);
setaccuracy(90);
setspeed(25);
}
void Archer::attack()
{
cout << "Arrow attack!";
cout << getdamage() << "의 피해를 주었다." << endl;
}
void Archer::givedamage(Player* player)
{ // 궁수는 공격 횟수 3번으로 데미지 나누기 3을함
Damage = (Power - player->getdefence()) / 3;
if (Damage <= 0)
{
Damage = 1;
}
}
// Thief.cpp
#include "Thief.h"
using namespace std;
void Thief::initStats()
{
setjob_name("도적");
setlevel(1);
setnickname(nickname);
setHP2(100);
setMP(80);
setpower(50);
setdefence(5);
setaccuracy(80);
setspeed(35);
}
void Thief::attack()
{
cout << "speed attack!";
cout << getdamage() << "의 피해를 주었다." << endl;
}
void Thief::givedamage(Player* player)
{ // 도적은 공격 횟수 5번으로 데미지 나누기 5를 함.
Damage = (Power - player->getdefence()) / 5;
if (Damage <= 0)
{
Damage = 1;
}
}
몬스터(Monster)
// Monster.h
#pragma once
#include "Player.h"
class Monster:public Player
{
public:
Monster(std::string name);
virtual void attack() override; // Player의 attack을 재정의
virtual void givedamage(Player* player) override;
};
//Monster.cpp
#include "Monster.h"
using namespace std;
Monster::Monster(std::string name) // 몬스터의 이름 매개변수로 입력, 기초 능력치
{
nickname = name;
setHP2(50);
setpower(30);
setdefence(10);
setspeed(10);
}
void Monster::attack()
{
cout << "몬스터가 공격했다." << endl;
cout << "플레이어에게" << getdamage() << "의 피해를 주었다." << endl; // 데미지 출력
}
void Monster::givedamage(Player* player) // 플레이어 객체의 포인터 매개변수로 입력
{
Damage = Power - player->getdefence(); // 몬스터의 공격력 - 플레이어의 방어력 = 데미지
if (Damage <= 0) // 데미지 0 이하라면 데미지 1로 정의
{
Damage = 1;
}
}
main
#include "Player.h"
#include "Warrior.h"
#include "Magician.h"
#include "Thief.h"
#include "Archer.h"
#include "Monster.h"
using namespace std;
// 메인 함수
int main()
{
Warrior wa;
Archer ar;
Magician ma;
Thief th;
Player* player[4] = {&wa, &ar, &ma, &th}; // Player 타입의 포인터 배열 선언
Player* job = nullptr;
Player* monster = new Monster("슬라임"); // 몬스터의 이름은 슬라임
int job_choice;
string name;
cout << "이름을 입력하세요." << endl;
cin >> name;
cout << "1.전사 2.궁수 3.마법사 4.도적" << endl << "직업 선택: ";
cin >> job_choice;
if (job_choice >= 1 && job_choice <= 4)
{
job = player[job_choice - 1];
}
else
{
cout << "잘못된 입력입니다.";
return 0;
}
if (job != nullptr)
{
job->setnickname(name);
job->initStats();
job->printPlayerStatus();
}
int choice = 0;
int Player_hp = job->getHP(); //setHP의 매개변수에 넣기위한 변수
int Monster_hp = monster->getHP(); //setHP의 매개변수에 넣기위한 변수
while (choice < 3)
{
cout << "행동을 고르세요. 1. 플레이어가 공격 2. 슬라임이 공격" << endl;
cin >> choice;
switch (choice)
{
case 1: // 플레이어가 몬스터를 공격했을 때
if (job == player[1]) // 직업이 궁수라면
{
for (int i = 0; i < 3; i++)
{
job->givedamage(monster);
Monster_hp = monster->getHP() - job->getdamage();
monster->setHP2(Monster_hp);
job->attack();
}
}
else if (job == player[3]) // 직업이 도적이라면
{
for (int i = 0; i < 5; i++)
{
job->givedamage(monster);
Monster_hp = monster->getHP() - job->getdamage();
monster->setHP2(Monster_hp);
job->attack();
}
}
else if (job == player[0] || job == player[2]) // 직업이 전사, 마법사라면
{
job->givedamage(monster);
Monster_hp = monster->getHP() - job->getdamage();
monster->setHP2(Monster_hp);
job->attack();
}
if (monster->setHP(Monster_hp)) // 몬스터 생존 여부 판단
{
cout << monster->getname() <<"의 남은 HP: " << Monster_hp << endl;
}
else
{
cout << monster->getname() << "을(를) 처치했습니다. 플레이어의 승리입니다." << endl;
return 0;
}
break;
case 2: // 슬라임이 플레이어를 공격했을 때
monster->givedamage(job);
if (job->setHP(Player_hp))
{ // 플레이어가 피
Player_hp = job->getHP() - monster->getdamage();
job->setHP2(Player_hp);
if (job->setHP(Player_hp)) // 플레이어 생존 여부 판단
{
monster->attack();
cout << "플레이어의 남은 HP: " << Player_hp << endl;
}
else
{ // 플레이어 사망시 플레이어의 남은 HP와 몬스터의 승리문구 출력
Player_hp = 0;
cout << "플레이어의 HP: " << Player_hp << endl;
cout << monster->getname() << "의 승리입니다." << endl;
return 0;
}
}
break;
}
}
}
결과
몬스터의 방어력은 10이다.
전사(법사 동일)
궁수
도적
'숙제' 카테고리의 다른 글
C++ 숙제(오버로딩 된 함수 템플릿으로 변경하기) (1) | 2025.08.19 |
---|---|
C++ 숙제(메모리 누수 발생 코드 분석하고 보완하기, 스마트 포인터를 활용한 로그분석기 구현) (0) | 2025.08.19 |
C++ 1번 과제(상태창 구현하기) (2) | 2025.08.15 |
C++ 숙제 (핸드폰 정보 출력 프로그램 구현하기) (2) | 2025.08.14 |
C++ 숙제(다형성을 활용한 게임 스킬 사용 프로그램 구현하기) (2) | 2025.08.14 |