1. Day14

  • C++ 문법 학습
  • 1, 2번 과제 제출 및 해설
  • 3, 4번 과제 발제
  • CH2 학습 가이드 - 12/16

2. C++ 문법 학습(Day14)

  • 게임 개발자를 위한 C++ 문법(2-4)
    • 객체지향적 설계
      • SOLID 원칙

3. 1, 2번 과제 제출 및 해설

  • 1번 과제 : 상태창 구현
#include <iostream>

using namespace std;

#pragma region 함수 모음
void setPotion(int count, int* p_HPPotion, int* p_MPPotion)
{
    // 포션 지급
    *p_HPPotion = count;
    *p_MPPotion = count;
}

void supplyPotion(int* p_HPPotion, int* p_MPPotion)
{
    //포션 하나씩 추가
    *p_HPPotion += 1;
    *p_MPPotion += 1;
}
#pragma endregion 

int main()
{
#pragma region 변수 선언
    // 0 == HP, 1 == MP, 2 == 공격력, 3 == 방어력, 4 == 힘 들을 0 으로 초기화
    int status[5] = {};
    // 레벨 과 레벨업 포인트
    int Lv = 1;
    int LvPoint = 0;
    // HP포션 MP포션
    int HPPotion = 0;
    int MPPotion = 0;
    // HP MP 값 충족 체크(둘다 50 초과)
    bool HPMPPassed = false;
    // 공격력 방어력 값 충족 체크(둘다 0 초과)
    bool AtkDefPassed = false;
    // 힘 입력 값 충족 체크
    bool str = false;
    // HP포션 MP 포션 최초 지급 체크
    bool Potion = false;
#pragma endregion
    // 게임 루프 진입
    while (true)
    {

#pragma region 초기입력
        // HPMP 입력
        if (HPMPPassed == false)
        {
            cout << "HP와 MP를 입력해 주세요: ";
            cin >> status[0] >> status[1];

            if (status[0] > 50 && status[1] > 50)
            {
                HPMPPassed = true;
            }
            else
            {
                cout << "HP나 MP의 값이 너무 작습니다. 다시 입력해주세요." << '\n';
            }
            continue;
        }

        // 공격력 방어력 입력
        if (AtkDefPassed == false)
        {


            cout << "공격력과 방어력을 입력해주세요: ";
            cin >> status[2] >> status[3];

            if (status[2] > 0 && status[3] > 0)
            {
                AtkDefPassed = true;
            }
            else
            {
                cout << "공격력과 방어력 값이 너무 작습니다. 다시 입력해주세요." << '\n';
            }
            continue;
        }

        // 힘 입력
        if (str == false)
        {


            cout << "str: ";
            cin >> status[4];

            if (status[4] > 0)
            {
                str = true;
            }
            else
            {
                cout << "힘 값이 너무 작습니다. 다시 입력해주세요." << '\n';
            }
            continue;
        }

        // 포션 지급(5개씩)
        if (Potion == false)
        {
            // 포션 지급 함수 호출
            setPotion(5, &HPPotion, &MPPotion);
            // 포션 지급 완료
            Potion = true;

            cout << "* 포션이 지급되었습니다. (HP, MP 포션 각 5개)" << '\n';
        }
#pragma endregion

#pragma region 시스템 화면
        // 시스템 화면
        cout << "=============================================" << '\n';
        cout << "<스탯 관리 시스템>" << '\n';
        cout << "1. HP UP" << '\n';
        cout << "2. MP UP" << '\n';
        cout << "3. 공격력 UP" << '\n';
        cout << "4. 방어력 UP" << '\n';
        cout << "5. 현재 능력치" << '\n';
        cout << "6. Level UP" << '\n';
        cout << "7. STR UP" << '\n';
        cout << "0. 나가기" << '\n';
#pragma endregion    

#pragma region 입력 로직 

        // 시스템 입력 정수 한번만 선언 되면 되기 때문에 while문의 밖에
        int cmd;

        while (true)
        {
            cout << "번호를 선택해주세요: ";
            cin >> cmd;
            // 선택지에 번호 마다 기능 구현 0 ~ 7 이외는 다시 입력하도록
            switch (cmd)
            {
            case 1:
                // HP 포션 사용
                if (HPPotion > 0)
                {
                    status[0] += 20;
                    HPPotion--;
                    cout << "* HP가 20 증가되었습니다. 포션이 1개 차감됩니다." << '\n';
                    cout << "현재 HP: " << status[0] << '\n';
                    cout << "남은 포션 수: " << HPPotion << '\n';
                }
                else
                {
                    cout << "포션이 부족합니다." << '\n';
                }
                break;
            case 2:
                // MP 포션 사용
                if (MPPotion > 0)
                {
                    status[1] += 20;
                    MPPotion--;
                    cout << "* MP가 20 증가되었습니다. 포션이 1개 차감됩니다." << '\n';
                    cout << "현재 MP: " << status[1] << '\n';
                    cout << "남은 포션 수: " << MPPotion << '\n';
                }
                else
                {
                    cout << "포션이 부족합니다." << '\n';
                }
                break;
            case 3:
                // 공격력 2배 증가
                status[2] *= 2;
                cout << "* 공격력이 2배로 증가되었습니다." << '\n';
                cout << "현재 공격력: " << status[2] << '\n';

                break;
            case 4:
                // 방어력 2배 증가
                status[3] *= 2;
                cout << "* 방어력이 2배로 증가되었습니다." << '\n';
                cout << "현재 방어력: " << status[3] << '\n';
                break;
            case 5:
                // 현재 능력치
                cout << "현재 Lv : " << Lv << ", " << "HP : " << status[0] << ", " << "MP : " << status[1] << ", ";
                cout << "공격력 : " << status[2] << ", " << "방어력 : " << status[3] << ", " << "STR : " << status[4] <<'\n';
                cout << "남은 HP/MP 포션 수 : " << HPPotion << "/" << MPPotion << '\n';
                break;
            case 6:
                //레벨업 및 포션 추가
                Lv++;
                supplyPotion(&HPPotion, &MPPotion);
                cout << "* 레벨업! HP/MP 포션이 지급됩니다." << '\n';
                cout << "남은 HP/MP 포션 수 : " << HPPotion << "/" << MPPotion << '\n';
                break;
            case 7:
                // 힘 증가
                status[4] += 10;
                cout << "* STR이 10 증가되었습니다." << '\n';
                cout << "현재 STR: " << status[4] << '\n';
                break;
            case 0:
                cout << "프로그램을 종료합니다." << '\n';
                return 0;
            default:
                cout << "잘못된 입력입니다." << '\n';
                break;
            }
        }

    }
#pragma endregion

    return 0;
}
  • 2번 과제 : 전직 시스템과 전투 시스템 구현
// Player.h/cpp
#pragma once
#include <string>

class Monster;

using namespace std;

class Player {
public:
    // 부모 생성자에서는 닉네임만 초기화(한줄로 끝나기 때문에 헤더에 정의)
    Player(string nickname) : nickname(nickname) {}

    virtual void attack() = 0;
    virtual void attack(Monster* monster) = 0;
    void printPlayerStatus();

    // getter 함수 (한줄로 끝나기 때문에 헤더에 정의)
    string getJobName() const { return job_name; }
    string getNickname() const { return nickname; }
    int getLevel() const { return level; }
    int getHP() const { return HP; }
    int getMP() const { return MP; }
    int getPower() const { return power; }
    int getDefence() const { return defence; }
    int getAccuracy() const { return accuracy; }
    int getSpeed() const { return speed; }

    // setter 함수 (한줄로 끝나기 때문에 헤더에 정의)
    void setNickname(string nickname) { this->nickname = nickname; }
    void setHP(int HP) { this->HP = HP; }
    void setMP(int MP) { this->MP = MP; }
    void setPower(int power) { this->power = power; }
    void setDefence(int defence) { this->defence = defence; }
    void setAccuracy(int accuracy) { this->accuracy = accuracy; }
    void setSpeed(int speed) { this->speed = speed; }

protected:
    // 멤버 변수
    string job_name;
    string nickname;
    int level;
    int HP;
    int MP;
    int power;
    int defence;
    int accuracy;
    int speed;
};

#include "Player.h"
#include <iostream>

void Player::printPlayerStatus()
{
    // Status 출력
    cout << "------------------------------------" << '\n';
    cout << "* 현재 능력치" << '\n';
    cout << "닉네임: " << nickname << '\n';
    cout << "Lv. " << level << '\n';
    cout << "HP: " << HP << '\n';
    cout << "MP: " << MP << '\n';
    cout << "공격력: " << power << '\n';
    cout << "방어력: " << defence << '\n';
    cout << "정확도: " << accuracy << '\n';
    cout << "속도: " << speed << '\n';
    cout << "------------------------------------" << '\n';
}

// Archer.h/cpp
#pragma once
#include <string>
#include "Player.h"

using namespace std;

class Archer : public Player
{
public:
    Archer(string nickname);

    void attack() override;
    void attack(Monster* monster) override;
};

#include "Archer.h"
#include "Monster.h"
#include <algorithm>
#include <iostream>

Archer::Archer(string nickname) : Player(nickname)
{
    job_name = "궁수";
    level = 5;
    setHP(100);
    setMP(100);
    setPower(13);
    setDefence(15);
    setAccuracy(80);
    setSpeed(50);
}

void Archer::attack()
{
    cout << "궁수 공격: " << power << '\n';
}

void Archer::attack(Monster* monster)
{
    // 최소 damage가 1이 되도록
    int damage = max(1, getPower() - monster->getDefence());

    // 직업 군마다 단일 공격과 다단히트 공격으로 출력 다단히트의 경우 공격력 / 공격 횟수를 틱당 damage로 출력
    for (int i = 0; i < 3; i++)
    {
        cout << monster->getName() <<"에게 화살로 " << damage / 3 << "의 피해를 입혔다!" << '\n';
    }

    // 몬스터의 HP set
    monster->setHP(monster->getHP() - damage);
    // 몬스터가 생존했으면 남은 HP 출력 해치웠다면 플레이어 승리 선언
    if (monster->getHP() > 0)
    {
        cout << monster->getName() << "의 남은 HP: " << monster->getHP() << '\n';
    }
    else
    {
        cout << getNickname() << "의 승리!" << '\n';
    }

}

// Monster.h/cpp
#pragma once
#include <string>

class Player;

using namespace std;

class Monster {
public:
    // Monster 생성자
    // - 몬스터의 이름을 매개변수로 입력 받습니다.
    // - 모든 몬스터는 HP 10, 공격력 30, 방어력 10, 스피드 10의 능력치를 가집니다.
    Monster(string name);

    // 몬스터의 공격 함수
    // - 플레이어 객체 포인터를 매개변수로 입력 받습니다.
    // - 몬스터의 공격력-플레이어의 방어력을 데미지로 정의합니다.
    // - 만약 위에서 계산한 데미지가 0 이하라면, 데미지를 1로 정의합니다.
    // - 플레이어에게 얼마나 데미지를 입혔는지 출력합니다.
    // - 플레이어 객체의 getHP 함수를 실행하여 플레이어HP-데미지 계산 결과를
    // - 플레이어 객체의 setHP 매개변수로 전달합니다.
    // - 플레이어가 생존했을 경우, 플레이어의 남은 HP를 출력합니다.
    void attack(Player* player);

    // 몬스터의 속성값을 리턴하는 get 함수(한줄로 끝나기 때문에 헤더에 정의)
    string getName() { return name; }
    int getHP() { return HP; }
    int getPower() { return power; }
    int getDefence() { return defence; }
    int getSpeed() { return speed; }

    // 몬스터의 속성값을 정의하는 set 함수(한줄로 끝나기 때문에 헤더에 정의)
    void setName(string name) { this->name = name; }
    void setHP(int HP) { this->HP = HP; }
    void setPower(int power) { this->power = power; }
    void setDefence(int defence) { this->defence = defence; }
    void setSpeed(int speed) { this->speed = speed; }

protected:
    string name; // 몬스터의 이름
    int HP; // 몬스터의 HP
    int power; // 몬스터의 공격력
    int defence; // 몬스터의 방어력
    int speed; // 몬스터의 스피드
};

#include "Monster.h"
#include "Player.h"
#include <iostream>
#include <algorithm>

using namespace std;

Monster::Monster(string name) : name(name)
{
    // 몬스터 이름을 제외한 나머지 변수 초기화
    setHP(10);
    setPower(30);
    setDefence(10);
    setSpeed(10);
}

void Monster::attack(Player* player)
{
    // 최소 damage가 1이 되도록 
    int damage = max(1, getPower() - player->getDefence());

    cout << player->getNickname()<< "에게" << damage << "의 피해를 입혔다!" << '\n';
    // 플레이어의 HP set
    player->setHP(player->getHP() - damage);
    // 플레이어 생존하면 플레이어의 남의 HP 출력
    if (player->getHP() > 0)
    {
        cout << "플레이어의 남은 HP: " << player->getHP() << '\n';
    }


}

// main.cpp
#include <iostream>
#include "player.h"
#include "warrior.h"
#include "Magician.h"
#include "thief.h"
#include "Archer.h"
#include "Monster.h"

using namespace std;

// 메인 함수
int main() {
    string jobs[] = { "전사", "마법사", "도적", "궁수" };
    int job_choice = 0;
    string nickname;

    Player* player = nullptr;

    cout << "* 닉네임을 입력해주세요: ";
    cin >> nickname;

    cout << "<전직 시스템>" << endl;
    cout << nickname << "님, 환영합니다!" << endl;
    cout << "* 원하시는 직업을 선택해주세요." << endl;

    for (int i = 0; i < 4; i++) {
        cout << (i + 1) << ". " << jobs[i] << endl;
    }

    cout << "선택: ";
    cin >> job_choice;

    switch (job_choice) {
    case 1:
        player = new Warrior(nickname);
        break;
    case 2:
        player = new Magician(nickname);
        break;
    case 3:
        player = new Thief(nickname);
        break;
    case 4:
        player = new Archer(nickname);
        break;
    default:
        cout << "잘못된 입력입니다." << endl;
        return 1;
    }

    // 플레이어 직업 생성 후 몬스터 생성
    Monster* monster = new Monster("슬라임");

    // 몬스터가 플레이어 먼저 공격(몬스터가 더 약하기 때문)
    monster->attack(player);

    // 플레이어가 살아있다면 몬스터 대상 공격(도적은 슬라임에게 죽기때문에 공격이 안됨)
    if (player->getHP() > 0)
    {
        player->attack(monster);
    }

    // 플레이어 Status 표기
    player->printPlayerStatus();

    // 플레이어 동적할당 해제 스위치 문에서 캐릭터 생성이 안될 수 있기때문에 체크
    if (player != nullptr)
        delete player;
    // 몬스터는 반드시 생성하기 때문에 해제
    delete monster;

    return 0;
}

  • 3, 4번 과제 발제

    • 인벤토리 시스템 구현
    • 연금술 공방 관리 시스템 구현

4. CH2 학습 가이드

  • 미니 실습
#include <iostream>
#include <string>
#include <vector>

using namespace std;  

class LifetimeChecker
{
private:
    string name;

public:
    LifetimeChecker(string checkerName) : name(checkerName)
    {
        cout << name << " + Constructor" << '\n';
    }

    ~LifetimeChecker()
    {
        cout << name << " + Destructor" << '\n';
    }
};

int main() 
{
    LifetimeChecker localChecker("Local");
    LifetimeChecker* pChecker = new LifetimeChecker("Dynamic");

    for (int i = 0; i < 3; i++)
    {
        LifetimeChecker forChecker("For");
    }

    delete pChecker;
    return 0;
}

5. 내일 계획 : 3번과제 시작, 알고리즘 풀이

+ Recent posts