오늘은 추가적으로 게임에 컨셉에 맞게 weapon 클래스 와 skill 클래스 을 추가적으로 구현했다.
아이디어를 계속 교환 하던 중에 스킬이 있으면 좋을 것 같다고 해서 총 세가지 스킬을 구상했다.
- 데미지 세배 공격(TrippleDamage)
- cc기인 속박 스킬(BindSkill)
- 적의 공격을 카운터 치는 스킬(counterstrike)
2번 스킬은 적의 속도를 50% 낮추며 선제 공격을 할 수 있게 해주는 디버프 스킬이며
3번 카운터 스킬은 적보다 speed가 높을 시에 적의 공격력 + 나의 공격력을 적에게 받아치는 스킬이다. 하지만, 적 보다 속도가 낮을 시에는 체력이 깎인다. 따라서, pressure 압력이 100이 됐을 때 속도가 낮아지는 데 이때는 이 스킬이 무용지물이다.
이런 기획을 가지고 코드를 작성하게 됐다.
#pragma once
#include <string>
class Monster;
enum class WeaponType { FLASH, VANTA_BLACK, EXPLOSIVE_GUN, NONE };
class Weapon {
protected:
std::string name;
WeaponType type;
int addDamage;
public:
Weapon(std::string n, WeaponType t, int d, int bc)
: name(n)
, type(t)
, addDamage(d) {
}
virtual ~Weapon() {} // 상속 시
// 공통 정보 조회
std::string getName() const { return name; }
WeaponType getType() const { return type; }
int getAddDamage() const { return addDamage; }
};
class Flashbang : public Weapon {
public:
Flashbang();
};
class Vantablack : public Weapon {
public:
Vantablack();
};
class WaterGun : public Weapon {
public:
WaterGun();
};
#include "Weapon.h"
#include "Monster.h"
#include "GameLogger.h"
#include <iostream>
//// 섬광탄 (Flashbang)
Flashbang::Flashbang() : Weapon("섬광탄", WeaponType::FLASH, 30) {}
//int Flashbang::calculateDamage(int baseAttack, const Monster* target) const {
// int total = baseAttack + addDamage;
// // MonsterStat의 type이 Hidden(은닉형)이면 2배 데미지
// if (target && target->getMonsterType() == AttributeType::Hidden) {
// std::cout << "\n 섬광이 은닉한 적을 밝혀냅니다! (데미지 2배)" << std::endl;
// return total * 2;
// }
// return total;
//}
//
//// 반타블랙 (Vantablack)
Vantablack::Vantablack() : Weapon("반타블랙 검", WeaponType::VANTA_BLACK, 35) {}
//int Vantablack::calculateDamage(int baseAttack, const Monster* target) const {
// int total = baseAttack + addDamage;
// // Luminous(발광형)에게 2배
// if (target && target->getMonsterType() == AttributeType::Luminous) {
// std::cout << "\n 반타블랙이 적의 빛을 흡수합니다! (데미지 2배)" << std::endl;
// return total * 2;
// }
// return total;
//}
//
//// 폭발형 수총 (WaterGun)
WaterGun::WaterGun() : Weapon("폭발형 수총", WeaponType::EXPLOSIVE_GUN, 50) {}
//int WaterGun::calculateDamage(int baseAttack, const Monster* target) const {
// int total = baseAttack + addDamage;
// // Giant(거대형)에게 2배
// if (target && target->getMonsterType() == AttributeType::Giant) {
// std::cout << "\n 압축 폭발이 거대한 외피를 뚫습니다! (데미지 2배)" << std::endl;
// return total * 2;
// }
// return total;
//}
먼저 본래 상성 관계의 데미지 강화 로직을 무기에 세팅을 했다가 gamesystem으로 옮기게 됐다.
#pragma once
#include <string>
#include <memory>
#include <iostream>
class Player;
class Monster;
class Skill
{
protected:
std::string name;
public:
Skill(std::string n);
virtual ~Skill();
virtual void execute(Player* player, Monster* target) = 0;
std::string getName() const { return name; }
};
class TripleDamageSkill : public Skill {
public:
TripleDamageSkill();
void execute(Player* player, Monster* target) override;
};
class BindSkill : public Skill {
public:
BindSkill();
void execute(Player* player, Monster* target) override;
};
class CounterSkill : public Skill {
public:
CounterSkill();
void execute(Player* player, Monster* target) override;
};
#include "Skill.h"
#include "Player.h"
#include "Monster.h"
Skill::Skill(std::string n) : name(n) {}
Skill::~Skill() {}
TripleDamageSkill::TripleDamageSkill() : Skill("파워 스트라이크") {}
BindSkill::BindSkill() : Skill("그물 속박") {}
CounterSkill::CounterSkill() :Skill("크로스 카운터") {}
void TripleDamageSkill::execute(Player* player, Monster* target) {
if (!player || !target) return;
int enhancedDamage = player->getAttack() * 3;
std::cout << "[스킬] " << name << " 발동!" << std::endl;
std::cout << "강력한 일격이 " << target->getName() << " 에게 " << enhancedDamage << "의 피해를 입힙니다!" << std::endl;
target->takeDamage(enhancedDamage);
}
void BindSkill::execute(Player* player, Monster* target) {
if (!player || !target) return;
// 몬스터 속도 감소
int currentMonsterSpeed = target->getSpeed();
int reducedSpeed = currentMonsterSpeed / 2;
target->setSpeed(reducedSpeed);
std::cout << "[스킬] " << name << " 발동!!" << std::endl;
std::cout << target->getName() << "의 움직임이 둔해졌습니다! (속도: " << currentMonsterSpeed << " -> " << reducedSpeed << ")" << std::endl;
}
void CounterSkill::execute(Player* player, Monster* target) {
if (!player || !target) return;
if (player->getSpeed() > target->getSpeed()) {
int counterDamage = target->getAttack() + player->getAttack();
std::cout << "[스킬] " << name << " 발동!" << std::endl;
std::cout << "적의 공격을 읽고 카운터를 날립니다!" << std::endl;
std::cout << "데미지 계산: [적 ATK " << target->getAttack()
<< "] + [내 ATK " << player->getAttack() << "]" << std::endl;
target->takeDamage(counterDamage);
}
else {
std::cout << "적의 속도가 너무 빠릅니다! 카운터에 실패했습니다..... 역습이 허용됐습니다" << std::endl;
//실패 시 체력을 깍음
player->takeDamage(20);
}
}
작성 한거 와 같이 스킬을 구현 했다.
스킬을 얻는 방식은 기존에 levelUp 함수와 연동해서 3, 6, 9렙이 됐을 때 렌덤한 스킬을 배울 수 있고 총 1개의 스킬만 배울 수 있도록 만들었다.
void Player::levelUp() {
level++;
int hpBonus = level * 20;
int atkBonus = level * 5;
maxHp += hpBonus;
baseAttack += atkBonus;
hp = maxHp;
exp -= maxExp;
if (exp < 0) exp = 0;
cout << "=============================" << endl;
cout << "Level UP!!! 현재 레벨: " << level << endl;
cout << "최대 체력 " << hpBonus << " 증가 / 공격력 " << atkBonus << " 증가" << endl;
cout << "=============================" << endl;
if (level == 3 || level == 6 || level == 9) {
cout << "특정 레벨 도달! 고대의 기술 중 하나를 연마할 수 있습니다." << endl;
int skillIdx = Random::getRandomValue(1, 3);
unique_ptr<Skill> discoveredSkill;
switch (skillIdx) {
case 1:
discoveredSkill = make_unique<TripleDamageSkill>();
break;
case 2:
discoveredSkill = make_unique<BindSkill>();
break;
case 3:
discoveredSkill = make_unique<CounterSkill>();
break;
}
cout << "새롭게 발견한 기술 : [" << discoveredSkill->getName() << "] " << endl;
this->learnSkill(move(discoveredSkill));
}
}
//무기 장착 구현
void Player::setWeapon(std::unique_ptr<Weapon> newWeapon) {
if (!newWeapon) return;
equippedWeapon = std::move(newWeapon);
cout << name << " 대원이 " << equippedWeapon->getName() << "무기를 장착했습니다";
}
//스킬 배우기
void Player::learnSkill(unique_ptr<Skill> newSkill) {
if (!newSkill) return;
if (currentSkill) {
cout << "---------------------------------------------" << endl;
cout << "이미 스킬[" << currentSkill->getName() << "]을 보유 중입니다." << endl;
cout << "새 스킬 [" << newSkill->getName() << "]로 교체하시겠습니까?" << endl;
cout << "1. 교체한다 (기존 기술 삭제) 2. 유지한다 (새 기술 버림)" << endl;
if (InputSystem::getInputInt(1, 2) == 1) {
currentSkill = move(newSkill);
cout << "새로운 스킬을 배웠습니다!" << endl;
}
else {
cout << "기존 스킬을 유지합니다." << endl;
}
}
else {
currentSkill = move(newSkill);
cout << "\n스킬 [" << currentSkill->getName() << "]을 습득했습니다!\n";
}
}
// 스킬 사용
void Player::useSkill(Monster* target) {
if (currentSkill) {
currentSkill->execute(this, target);
}
else {
std::cout << "배운 스킬이 없어 사용할 수 없습니다.\n";
}
}
오늘 여러 문제들이 발생했다.
- merge 중 충돌
- visual studio 솔루션 탐색기에 파일이 안뜨는 문제(이것 또한 잘 못된 머지 문제)
여러 사람이 작업을 동시에 하기 때문에 여러 프로젝트가 동시에 pull request 하는 경우도 있고 제일 최근의 main branch를 본인 branch 에 update 안해놓은 경우도 있어 고통에 시간을 보냈습니다.
하지만, 이번 기회에 깃 관리를 담당하며 많이 배우게 됐고 제가 충돌을 알아서 해결하며 merge하는 법도 배우며 이로운 시간 이였습니다.
'언리얼' 카테고리의 다른 글
| C++) TRPG 최종 (0) | 2026.04.01 |
|---|---|
| C++) TRPG#04 : 패치 및 수정 (0) | 2026.03.30 |
| C++) TRPG #02 : 플레이어 클래스 생성 (0) | 2026.03.26 |
| C++) TRPG #01 : 기획 (0) | 2026.03.25 |
| TRPG C++ (0) | 2026.03.23 |