commit d8bb7c4b31b215f35bddb2d08ad69b91e1cd2513 Author: ChoWooYeon Date: Wed May 6 00:02:19 2026 +0900 add Files diff --git a/C++Project.sln b/C++Project.sln new file mode 100644 index 0000000..33bb4f7 --- /dev/null +++ b/C++Project.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.37111.16 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TextRPG", "TextRPG\TextRPG.vcxproj", "{9BEB22C7-CB82-42BD-B210-C21100FC86BF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9BEB22C7-CB82-42BD-B210-C21100FC86BF}.Debug|x64.ActiveCfg = Debug|x64 + {9BEB22C7-CB82-42BD-B210-C21100FC86BF}.Debug|x64.Build.0 = Debug|x64 + {9BEB22C7-CB82-42BD-B210-C21100FC86BF}.Debug|x86.ActiveCfg = Debug|Win32 + {9BEB22C7-CB82-42BD-B210-C21100FC86BF}.Debug|x86.Build.0 = Debug|Win32 + {9BEB22C7-CB82-42BD-B210-C21100FC86BF}.Release|x64.ActiveCfg = Release|x64 + {9BEB22C7-CB82-42BD-B210-C21100FC86BF}.Release|x64.Build.0 = Release|x64 + {9BEB22C7-CB82-42BD-B210-C21100FC86BF}.Release|x86.ActiveCfg = Release|Win32 + {9BEB22C7-CB82-42BD-B210-C21100FC86BF}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {067C20FF-6880-47B6-AEA2-E4A9547E9041} + EndGlobalSection +EndGlobal diff --git a/TextRPG/Source/Common/CommonMemory.h b/TextRPG/Source/Common/CommonMemory.h new file mode 100644 index 0000000..953eaf3 --- /dev/null +++ b/TextRPG/Source/Common/CommonMemory.h @@ -0,0 +1,8 @@ +#pragma once + +template +void SafeDelete(T& P) +{ + delete P; + P = nullptr; +} \ No newline at end of file diff --git a/TextRPG/Source/Core/Interface/Damageable.h b/TextRPG/Source/Core/Interface/Damageable.h new file mode 100644 index 0000000..0b01eff --- /dev/null +++ b/TextRPG/Source/Core/Interface/Damageable.h @@ -0,0 +1,9 @@ +#pragma once + +class IDamageable +{ +public: + virtual void TakeDamage(int Amount) = 0; + virtual bool IsDead() = 0; + virtual void Reset() = 0; +}; diff --git a/TextRPG/Source/Core/Interface/Scene.h b/TextRPG/Source/Core/Interface/Scene.h new file mode 100644 index 0000000..bad2ed0 --- /dev/null +++ b/TextRPG/Source/Core/Interface/Scene.h @@ -0,0 +1,10 @@ +#pragma once + +class IScene +{ +public: + virtual void Enter() = 0; + virtual void Update() = 0; + virtual void Exit() = 0; + virtual void Release() = 0; +}; diff --git a/TextRPG/Source/Core/Item/Item.cpp b/TextRPG/Source/Core/Item/Item.cpp new file mode 100644 index 0000000..46674bb --- /dev/null +++ b/TextRPG/Source/Core/Item/Item.cpp @@ -0,0 +1,31 @@ +#include "Item.h" + +Item::Item() : + ItemData() +{ +} + +Item::Item(const ItemStatData& NewData) : + ItemData(NewData) +{ +} + +Item& Item::operator=(const Item& Other) +{ + this->ItemData.Name = Other.GetItemName(); + this->ItemData.Price = Other.GetItemPrice(); + + return *this; +} + +Item::~Item() +{ +} + +void Item::Initalize() +{ +} + +void Item::Release() +{ +} diff --git a/TextRPG/Source/Core/Item/Item.h b/TextRPG/Source/Core/Item/Item.h new file mode 100644 index 0000000..dae2b58 --- /dev/null +++ b/TextRPG/Source/Core/Item/Item.h @@ -0,0 +1,39 @@ +#pragma once +#include "Core/Object/GameObject.h" + +struct ItemStatData +{ + ItemStatData() = default; + ItemStatData(const std::string& ItemName, const int InPrice) : Name(ItemName), Price(InPrice){} + ItemStatData(const ItemStatData& other) : Name(other.Name), Price(other.Price) {} + ItemStatData(ItemStatData&& other) noexcept : Name(std::move(other.Name)), Price(other.Price) {} + + std::string Name; + int Price; +}; + +class Item : public GameObject +{ +public: + Item(); + Item(const ItemStatData& NewData); + Item& operator=(const Item& Other); + ~Item() override; + + static bool ComparePriceDesc(Item& A, Item& B) + { + return A.GetItemPrice() > B.GetItemPrice(); + } + + void Initalize() override; + void Release() override; + + bool Equals(const std::string& FindName){ return this->ItemData.Name == FindName; } + + std::string GetItemName() const { return ItemData.Name; } + int GetItemPrice() const { return ItemData.Price; } + +private: + ItemStatData ItemData; +}; + diff --git a/TextRPG/Source/Core/Object/GameObject.cpp b/TextRPG/Source/Core/Object/GameObject.cpp new file mode 100644 index 0000000..91b5ca8 --- /dev/null +++ b/TextRPG/Source/Core/Object/GameObject.cpp @@ -0,0 +1 @@ +#include "GameObject.h" diff --git a/TextRPG/Source/Core/Object/GameObject.h b/TextRPG/Source/Core/Object/GameObject.h new file mode 100644 index 0000000..49ac84a --- /dev/null +++ b/TextRPG/Source/Core/Object/GameObject.h @@ -0,0 +1,10 @@ +#pragma once + +class GameObject +{ +public: + GameObject() = default; + virtual ~GameObject() = default; + virtual void Initalize() = 0; + virtual void Release() = 0; +}; \ No newline at end of file diff --git a/TextRPG/Source/Core/Scene/CoreScene.cpp b/TextRPG/Source/Core/Scene/CoreScene.cpp new file mode 100644 index 0000000..eb9066c --- /dev/null +++ b/TextRPG/Source/Core/Scene/CoreScene.cpp @@ -0,0 +1,36 @@ +#include "CoreScene.h" + + +CoreScene::CoreScene(GameSceneManager* InOwner) : + Owner(nullptr), + bIsRunning(false), + bEnableTick(false) +{ + Owner = InOwner; +} + +CoreScene::~CoreScene() +{ + Release(); +} + +void CoreScene::Enter() +{ + bIsRunning = true; +} + +void CoreScene::Update() +{ + assert(0); // Not Implement. +} + +void CoreScene::Exit() +{ + assert(0); // Not Implement. +} + +void CoreScene::Release() +{ + Owner = nullptr; +} + diff --git a/TextRPG/Source/Core/Scene/CoreScene.h b/TextRPG/Source/Core/Scene/CoreScene.h new file mode 100644 index 0000000..0aad003 --- /dev/null +++ b/TextRPG/Source/Core/Scene/CoreScene.h @@ -0,0 +1,23 @@ +#pragma once +#include "Core/Interface/Scene.h" + +class GameSceneManager; +class CoreScene : public IScene +{ +public: + CoreScene() = default; + CoreScene(GameSceneManager* InOwner); + virtual ~CoreScene(); + + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; + + bool IsEnableTick() { return bEnableTick; } + +protected: + GameSceneManager* Owner; + bool bIsRunning; + bool bEnableTick; +}; diff --git a/TextRPG/Source/Core/Subsystems/GameDataManager.cpp b/TextRPG/Source/Core/Subsystems/GameDataManager.cpp new file mode 100644 index 0000000..605a817 --- /dev/null +++ b/TextRPG/Source/Core/Subsystems/GameDataManager.cpp @@ -0,0 +1,38 @@ +#include "pch.h" +#include "GameDataManager.h" + +#include "Core/Item/Item.h" +#include "Game/Characters/Monster/Monster.h" +#include "Game/Characters/Player/Player.h" + +GameDataManager::~GameDataManager() +{ + Release(); +} + +void GameDataManager::Initialize() +{ + PlayerData = new PlayerStatData(); +} + +void GameDataManager::Release() +{ + SafeDelete(PlayerData); + + for (auto It : MonsterDataMap) + { + SafeDelete(It.second); + } + MonsterDataMap.clear(); + + for (auto It : ItemDataMap) + { + SafeDelete(It.second); + } + ItemDataMap.clear(); +} + +void GameDataManager::SetPlayerData(PlayerStatData* NewPlayerData) +{ + PlayerData = NewPlayerData; +} diff --git a/TextRPG/Source/Core/Subsystems/GameDataManager.h b/TextRPG/Source/Core/Subsystems/GameDataManager.h new file mode 100644 index 0000000..491f137 --- /dev/null +++ b/TextRPG/Source/Core/Subsystems/GameDataManager.h @@ -0,0 +1,28 @@ +#pragma once + +struct PlayerStatData; +struct MonsterStatData; +struct ItemStatData; + +class GameDataManager +{ +public: + using MonsterDataCollection = std::unordered_map; + using ItemDataCollection = std::unordered_map; + +public: + GameDataManager() : PlayerData(nullptr){} + ~GameDataManager(); + + void Initialize(); + void Release(); + + PlayerStatData* GetPlayerData() { return PlayerData; } + + void SetPlayerData(PlayerStatData* NewPlayerData); + +private: + PlayerStatData* PlayerData; + MonsterDataCollection MonsterDataMap; + ItemDataCollection ItemDataMap; +}; diff --git a/TextRPG/Source/Core/Subsystems/GameInputSystem.cpp b/TextRPG/Source/Core/Subsystems/GameInputSystem.cpp new file mode 100644 index 0000000..cdac55e --- /dev/null +++ b/TextRPG/Source/Core/Subsystems/GameInputSystem.cpp @@ -0,0 +1,3 @@ +#include "pch.h" +#include "GameInputSystem.h" + diff --git a/TextRPG/Source/Core/Subsystems/GameInputSystem.h b/TextRPG/Source/Core/Subsystems/GameInputSystem.h new file mode 100644 index 0000000..7fc9dc9 --- /dev/null +++ b/TextRPG/Source/Core/Subsystems/GameInputSystem.h @@ -0,0 +1,80 @@ +#pragma once +#include "Data/Literals/Literals.h" + +class GameInputSystem; + +class InputSession +{ +public: + InputSession(GameInputSystem* InSystem) : InputSystem(InSystem) {} + InputSession(InputSession&& Other) noexcept : InputSystem(Other.InputSystem) {} + ~InputSession(); + + template + InputSession& operator>>(T& RHS); + + explicit operator bool() const; + +private: + GameInputSystem* InputSystem; +}; + +class GameInputSystem +{ +public: + GameInputSystem() : bFailed(false) {} + ~GameInputSystem() = default; + + bool IsFailed() const { return bFailed; } + void ApplyFail() { bFailed = true; } + void Reset() { bFailed = false; } + + void ClearBuffer() + { + std::cin.ignore(std::numeric_limits::max(), '\n'); + std::cin.clear(); + } + + template + InputSession operator>>(T& RHS) + { + InputSession session(this); + session >> RHS; + return session; + } + + template + GameInputSystem& operator<<(const T& RHS) + { + std::cout << RHS; + return *this; + } + +private: + bool bFailed; +}; + +inline InputSession::~InputSession() +{ + InputSystem->ClearBuffer(); +} + +inline InputSession::operator bool() const +{ + return !InputSystem->IsFailed(); +} + +template +InputSession& InputSession::operator>>(T& RHS) +{ + if (InputSystem->IsFailed()) return *this; + + std::cin >> RHS; + if (std::cin.fail()) + { + std::cout << Game::Common::ErrorInput << "\n"; + InputSystem->ClearBuffer(); + InputSystem->ApplyFail(); + } + return *this; +} \ No newline at end of file diff --git a/TextRPG/Source/Core/Subsystems/SceneManager.cpp b/TextRPG/Source/Core/Subsystems/SceneManager.cpp new file mode 100644 index 0000000..98a8878 --- /dev/null +++ b/TextRPG/Source/Core/Subsystems/SceneManager.cpp @@ -0,0 +1,36 @@ +#include "GameInstance.h" +#include "SceneManager.h" + +GameSceneManager::GameSceneManager() : + CurrentScene(nullptr) +{ +} + +GameSceneManager::~GameSceneManager() +{ + Release(); +} + +void GameSceneManager::Initialize() +{ +} + +void GameSceneManager::Update() +{ + if (!CurrentScene) return; + + if (CurrentScene->IsEnableTick()) + CurrentScene->Update(); +} + +void GameSceneManager::Release() +{ + for(auto It : SceneElements) + { + SafeDelete(It.second); + } + + SceneElements.clear(); + CurrentScene = nullptr; +} + diff --git a/TextRPG/Source/Core/Subsystems/SceneManager.h b/TextRPG/Source/Core/Subsystems/SceneManager.h new file mode 100644 index 0000000..04d3990 --- /dev/null +++ b/TextRPG/Source/Core/Subsystems/SceneManager.h @@ -0,0 +1,47 @@ +#pragma once + +#include "Core/Scene/CoreScene.h" + +#define CLASS_TO_NAME(Type) #Type + +class GameSceneManager +{ +public: + GameSceneManager(); + virtual ~GameSceneManager(); + + void Initialize(); + void Update(); + void Release(); + + template + void CreateScenes(); + + template + void TransitionTo(); + +private: + std::map SceneElements; + CoreScene* CurrentScene; +}; + +template +inline void GameSceneManager::CreateScenes() +{ + static_assert((std::is_base_of_v && ...), "반드시 CoreScene 클래스 이거나 상속받아야 함"); + (SceneElements.emplace(typeid(Scenes).name(), new Scenes(this)),...); +} + +template +inline void GameSceneManager::TransitionTo() +{ + static_assert((std::is_base_of_v), "반드시 CoreScene 클래스 이거나 상속받아야 함"); + + std::string ClassName = typeid(Scene).name(); + auto Found = SceneElements.find(ClassName); + if (Found != SceneElements.end()) + { + CurrentScene = Found->second; + CurrentScene->Enter(); + } +} \ No newline at end of file diff --git a/TextRPG/Source/Data/Literals/Literals.cpp b/TextRPG/Source/Data/Literals/Literals.cpp new file mode 100644 index 0000000..8d3479a --- /dev/null +++ b/TextRPG/Source/Data/Literals/Literals.cpp @@ -0,0 +1,2 @@ +#include "pch.h" +#include "Literals.h" diff --git a/TextRPG/Source/Data/Literals/Literals.h b/TextRPG/Source/Data/Literals/Literals.h new file mode 100644 index 0000000..8dbc5b1 --- /dev/null +++ b/TextRPG/Source/Data/Literals/Literals.h @@ -0,0 +1,106 @@ +#pragma once + +namespace Game +{ + namespace Common + { + const std::string Title = "===========================================\n" + " [ 던전 탈출 텍스트 RPG ]\n" + "===========================================\n"; + + const std::string ErrorInput = "잘못된 입력입니다 다시 입력해주세요.\n"; + const std::string SelectMenu = "번호를 선택해주세요\n"; + const std::string GameStart = "게임을 시작합니다!\n"; + const std::string PrepareInventorySave = "다음 단계에서 인벤토리에 저장됩니다.\n"; + const std::string InventorySave = "인벤토리에 저장되었습니다.\n"; + const std::string Return = "돌아가기\n"; + const std::string Levelup = "레벨업 조건 충족\n"; + const std::string GameClear = "게임 클리어!"; + const std::string GameOver = "게임 오버!"; + } + + namespace CreateCharacter + { + const std::string SelectVitality = "HP와 MP를 입력해주세요: "; + const std::string ErrorVitality = "HP나 MP의 값이 너무 작습니다. 다시 입력해주세요.\n"; + const std::string SelectCombatStats = "공격력과 방어력을 입력해주세요: "; + const std::string ErrorCombatStats = "공격력이나 방어력이 너무 작습니다. 다시 입력해주세요.\n"; + + const int MaxHP = 50; + const int MaxMP = 50; + const int MaxPower = 50; + const int MaxDefence = 50; + } + + namespace InitCharacterJob + { + const std::string MainMenuTitle = "< 전직 시스템 > \n"; + const std::string SelectJobGuide = "님, 직업을 선택해주세요!\n"; + const int AddMaxMP = 30; + const int AddMaxHP = 30; + const int AddMaxAttack = 50; + const int AddMaxDefence = 50; + } + namespace MainMenu + { + const std::string MainMenuTitle = "=== 메인 메뉴 === \n"; + const std::string EnterDungeon = "1. 던전 입장 \n"; + const std::string CheckInventory = "2. 인벤토리 확인 \n"; + const std::string EnterPotionShop = "3. 포션 제작소 \n"; + const std::string QuitGame = "0. 게임 종료 \n"; + } + namespace Dungeon + { + const std::string BattleStartTitle = "[ 전투 시작! ] \n"; + const std::string PlayerTurn = "--- 플레이어 턴 --- \n"; + const std::string TargetTurn = "--- 상대 턴 --- \n"; + const std::string Victory = "★ 전투 승리!\n"; + const std::string Loose = "T_T 전투 패배!\n"; + const std::string DropItemSaveGuide = "(다음 단계에서 인벤토리에 저장됩니다)\n"; + + namespace Slime + { + const std::string Name = "Slime"; + const std::string DropItemName = "슬라임 젤리"; + const int DropItemPrice = 10; + const int HP = 50; + const int Attack = 50; + const int Defence = 10; + } + namespace Orc + { + const std::string Name = "Orc"; + const std::string DropItemName = "오크의 심장"; + const int DropItemPrice = 30; + const int HP = 50; + const int Attack = 60; + const int Defence = 10; + } + namespace Goblin + { + const std::string Name = "Goblin"; + const std::string DropItemName = "고블린 나무망치"; + const int DropItemPrice = 50; + const int HP = 50; + const int Attack = 100; + const int Defence = 10; + } + namespace Dragon + { + const std::string Name = "Dragon"; + const std::string DropItemName = "None"; + const int DropItemPrice = 0; + const int HP = 30; + const int Attack = 20; + const int Defence = 10; + } + } + namespace Potion + { + + } + namespace ShowInventory + { + + } +} \ No newline at end of file diff --git a/TextRPG/Source/Game/Characters/Monster/Goblin/Goblin.cpp b/TextRPG/Source/Game/Characters/Monster/Goblin/Goblin.cpp new file mode 100644 index 0000000..45612e9 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Monster/Goblin/Goblin.cpp @@ -0,0 +1,45 @@ +#include "pch.h" +#include "Goblin.h" +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Data/Literals/Literals.h" + +Goblin::~Goblin() +{ +} + +Goblin::Goblin() +{ + MonsterData = MonsterStatData( + Game::Dungeon::Goblin::Name, + Game::Dungeon::Goblin::DropItemName, + Game::Dungeon::Goblin::HP, + Game::Dungeon::Goblin::Attack, + Game::Dungeon::Goblin::Defence, + Game::Dungeon::Goblin::DropItemPrice); +} + +Goblin::Goblin(MonsterStatData&& Desc) : + Monster(std::move(Desc)) +{ + +} + +void Goblin::Attack(class Player* Target) +{ + Monster::Attack(Target); +} + +void Goblin::Initalize() +{ +} + +void Goblin::Release() +{ + Monster::Release(); +} + +void Goblin::TakeDamage(int Amount) +{ + Monster::TakeDamage(Amount); +} \ No newline at end of file diff --git a/TextRPG/Source/Game/Characters/Monster/Goblin/Goblin.h b/TextRPG/Source/Game/Characters/Monster/Goblin/Goblin.h new file mode 100644 index 0000000..6dc7537 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Monster/Goblin/Goblin.h @@ -0,0 +1,14 @@ +#pragma once +#include "Game/Characters/Monster/Monster.h" + +class Goblin : public Monster +{ +public: + ~Goblin() override; + Goblin(); + Goblin(MonsterStatData&& Desc); + void Attack(class Player* Target) override; + void Initalize() override; + void Release() override; + void TakeDamage(int Amount) override; +}; diff --git a/TextRPG/Source/Game/Characters/Monster/Monster.cpp b/TextRPG/Source/Game/Characters/Monster/Monster.cpp new file mode 100644 index 0000000..28cbee6 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Monster/Monster.cpp @@ -0,0 +1,84 @@ +#include "pch.h" +#include "Monster.h" + +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Game/Characters/Player/Player.h" + +Monster::Monster(MonsterStatData&& Desc) : + MonsterData(std::move(Desc)) +{ + OriginalData = MonsterData; +} + +Monster::~Monster() +{ + Release(); +} + +void Monster::Attack(class Player* Target) +{ + GInput << MonsterData.Name << "이 공격했다! \n"; + system("pause"); + + std::string TargetName = Target->GetName(); + int TargetDefence = Target->GetDefence(); + int Damage = 0; + + Damage = (MonsterData.Attack - TargetDefence) < 0 ? 1 : (MonsterData.Attack - TargetDefence); + GInput << TargetName << "에게 " << Damage << " 데미지!" << "\n"; + GInput << TargetName << " HP: " << Target->GetHP() << " -> "; + Target->TakeDamage(Damage); + GInput << Target->GetHP() << "\n"; + system("pause"); +} + +void Monster::Release() +{ + +} + +void Monster::TakeDamage(int Amount) +{ + MonsterData.HP -= Amount; +} + +bool Monster::IsDead() +{ + return MonsterData.HP < 0; +} + +void Monster::Reset() +{ + MonsterData = OriginalData; +} + +std::string Monster::GetName() const +{ + return MonsterData.Name; +} + +std::string Monster::GetDropItemName() const +{ + return MonsterData.DropItemName; +} + +int Monster::GetDropItemPrice() const +{ + return MonsterData.DropItemPrice; +} + +int Monster::GetHP() const +{ + return MonsterData.HP; +} + +int Monster::GetAttack() const +{ + return MonsterData.Attack; +} + +int Monster::GetDefence() const +{ + return MonsterData.Defence; +} diff --git a/TextRPG/Source/Game/Characters/Monster/Monster.h b/TextRPG/Source/Game/Characters/Monster/Monster.h new file mode 100644 index 0000000..029f41b --- /dev/null +++ b/TextRPG/Source/Game/Characters/Monster/Monster.h @@ -0,0 +1,90 @@ +#pragma once +#include "Core/Interface/Damageable.h" +#include "Core/Object/GameObject.h" + +struct MonsterStatData; +struct ItemStatData; + +struct MonsterStatData +{ + MonsterStatData() : + HP(0), + Attack(0), + Defence(0), + DropItemPrice(0) + { + } + + MonsterStatData(const std::string& Name, const std::string& DropItemName, const int HP, const int Attack, const int Defence, const int DropItemPrice) : + Name(Name), + DropItemName(DropItemName), + HP(HP), + Attack(Attack), + Defence(Defence), + DropItemPrice(DropItemPrice) + { + } + + MonsterStatData(const MonsterStatData& Other) : + Name(Other.Name), + DropItemName(Other.DropItemName), + HP(Other.HP), + Attack(Other.Attack), + Defence(Other.Defence), + DropItemPrice(Other.DropItemPrice) + { + } + + MonsterStatData(MonsterStatData&& Other) noexcept : + Name(std::move(Other.Name)), + DropItemName(std::move(Other.DropItemName)), + HP(Other.HP), + Attack(Other.Attack), + Defence(Other.Defence), + DropItemPrice(Other.DropItemPrice) + { + } + + MonsterStatData& operator=(const MonsterStatData& Other) + { + (*this).Name = Other.Name; + (*this).DropItemName = Other.DropItemName; + (*this).HP = Other.HP; + (*this).Attack = Other.Attack; + (*this).Defence = Other.Defence; + (*this).DropItemPrice = Other.DropItemPrice; + return *this; + } + + std::string Name; + std::string DropItemName; + int HP; + int Attack; + int Defence; + int DropItemPrice; +}; + +class Monster : public GameObject, public IDamageable +{ +public: + Monster() = default; + Monster(MonsterStatData&& Desc); + ~Monster() override; + + virtual void Attack(class Player* Target); + virtual void Release(); + void TakeDamage(int Amount) override; + bool IsDead() override; + void Reset() override; + + std::string GetName() const; + std::string GetDropItemName() const; + int GetDropItemPrice() const; + int GetHP() const; + int GetAttack() const; + int GetDefence() const; + +protected: + MonsterStatData MonsterData; + MonsterStatData OriginalData; +}; diff --git a/TextRPG/Source/Game/Characters/Monster/Orc/Orc.cpp b/TextRPG/Source/Game/Characters/Monster/Orc/Orc.cpp new file mode 100644 index 0000000..3c6542a --- /dev/null +++ b/TextRPG/Source/Game/Characters/Monster/Orc/Orc.cpp @@ -0,0 +1,44 @@ +#include "pch.h" +#include "Orc.h" +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Data/Literals/Literals.h" + +Orc::~Orc() +{ +} + +Orc::Orc() +{ + MonsterData = MonsterStatData( + Game::Dungeon::Orc::Name, + Game::Dungeon::Orc::DropItemName, + Game::Dungeon::Orc::HP, + Game::Dungeon::Orc::Attack, + Game::Dungeon::Orc::Defence, + Game::Dungeon::Orc::DropItemPrice); +} + +Orc::Orc(MonsterStatData&& Desc) : + Monster(std::move(Desc)) +{ +} + +void Orc::Attack(Player* Target) +{ + Monster::Attack(Target); +} + +void Orc::Initalize() +{ +} + +void Orc::Release() +{ + Monster::Release(); +} + +void Orc::TakeDamage(int Amount) +{ + Monster::TakeDamage(Amount); +} \ No newline at end of file diff --git a/TextRPG/Source/Game/Characters/Monster/Orc/Orc.h b/TextRPG/Source/Game/Characters/Monster/Orc/Orc.h new file mode 100644 index 0000000..f5209e0 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Monster/Orc/Orc.h @@ -0,0 +1,14 @@ +#pragma once +#include "Game/Characters/Monster/Monster.h" + +class Orc : public Monster +{ +public: + ~Orc() override; + Orc(); + Orc(MonsterStatData&& Desc); + void Attack(Player* Target) override; + void Initalize() override; + void Release() override; + void TakeDamage(int Amount) override; +}; diff --git a/TextRPG/Source/Game/Characters/Monster/Slime/Slime.cpp b/TextRPG/Source/Game/Characters/Monster/Slime/Slime.cpp new file mode 100644 index 0000000..3f04095 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Monster/Slime/Slime.cpp @@ -0,0 +1,46 @@ +#include "pch.h" +#include "Slime.h" +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Data/Literals/Literals.h" +#include "Game/Characters/Player/Player.h" + + +Slime::~Slime() +{ +} + +Slime::Slime() +{ + MonsterData = MonsterStatData( + Game::Dungeon::Slime::Name, + Game::Dungeon::Slime::DropItemName, + Game::Dungeon::Slime::HP, + Game::Dungeon::Slime::Attack, + Game::Dungeon::Slime::Defence, + Game::Dungeon::Slime::DropItemPrice); +} + +Slime::Slime(MonsterStatData&& Desc) : + Monster(std::move(Desc)) +{ +} + +void Slime::Attack(Player* Target) +{ + Monster::Attack(Target); +} + +void Slime::Initalize() +{ +} + +void Slime::Release() +{ + Monster::Release(); +} + +void Slime::TakeDamage(int Amount) +{ + Monster::TakeDamage(Amount); +} \ No newline at end of file diff --git a/TextRPG/Source/Game/Characters/Monster/Slime/Slime.h b/TextRPG/Source/Game/Characters/Monster/Slime/Slime.h new file mode 100644 index 0000000..4024a2b --- /dev/null +++ b/TextRPG/Source/Game/Characters/Monster/Slime/Slime.h @@ -0,0 +1,14 @@ +#pragma once +#include "Game/Characters/Monster/Monster.h" + +class Slime : public Monster +{ +public: + ~Slime() override; + Slime(); + Slime(MonsterStatData&& Desc); + void Attack(Player* Target) override; + void Initalize() override; + void Release() override; + void TakeDamage(int Amount) override; +}; diff --git a/TextRPG/Source/Game/Characters/Player/Archer/Archer.cpp b/TextRPG/Source/Game/Characters/Player/Archer/Archer.cpp new file mode 100644 index 0000000..40ed269 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Archer/Archer.cpp @@ -0,0 +1,53 @@ +#include "Archer.h" +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Game/Characters/Monster/Monster.h" + +Archer::Archer(PlayerStatData&& Rvalue) : + Player(std::move(Rvalue)) +{ + HitCount = 3; +} + +Archer::~Archer() +{ +} + +void Archer::Initalize() +{ + Player::Initalize(); + + PlayerData.Job = "궁수"; + + int MaxAttack = Game::InitCharacterJob::AddMaxAttack; + GInput << "궁수로 전직하였습니다." << "(Attack +" << MaxAttack << ")" << "\n"; + GInput << "크리티컬 샷 추가!\n"; + PlayerData.Attack += MaxAttack; +} + +void Archer::Release() +{ + Player::Release(); +} + +void Archer::Attack(class Monster* Target) +{ + std::string TargetName = Target->GetName(); + int TargetDefence = Target->GetDefence(); + int Damage = 0; + + Damage = (PlayerData.Attack - TargetDefence) < 0 ? 1 : (PlayerData.Attack - TargetDefence) / HitCount; + GInput << "크리티컬 샷! -> " << TargetName << "에게 " << Damage << " 데미지! (x" << HitCount << ")" << "\n"; + + GInput << Target->GetName() << " HP: " << Target->GetHP() << " -> "; + for (int i = 0; i < HitCount; ++i) + Target->TakeDamage(Damage); + + GInput << Target->GetHP() << "\n"; + system("pause"); +} + +void Archer::TakeDamage(int Amount) +{ + Player::TakeDamage(Amount); +} \ No newline at end of file diff --git a/TextRPG/Source/Game/Characters/Player/Archer/Archer.h b/TextRPG/Source/Game/Characters/Player/Archer/Archer.h new file mode 100644 index 0000000..cf2e54f --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Archer/Archer.h @@ -0,0 +1,14 @@ +#pragma once +#include "Game/Characters/Player/Player.h" + +class Archer : public Player +{ +public: + Archer(PlayerStatData&& Rvalue); + ~Archer() override; + + void Initalize() override; + void Release() override; + void Attack(class Monster* Target) override; + void TakeDamage(int Amount) override; +}; diff --git a/TextRPG/Source/Game/Characters/Player/Mage/Mage.cpp b/TextRPG/Source/Game/Characters/Player/Mage/Mage.cpp new file mode 100644 index 0000000..6dce38c --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Mage/Mage.cpp @@ -0,0 +1,49 @@ +#include "Mage.h" +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Game/Characters/Monster/Monster.h" + +Mage::Mage(PlayerStatData&& Rvalue) : + Player(std::move(Rvalue)) +{ + HitCount = 1; +} + +Mage::~Mage() +{ +} + +void Mage::Initalize() +{ + Player::Initalize(); + + PlayerData.Job = "마법사"; + + int MaxMp = Game::InitCharacterJob::AddMaxMP; + GInput << "마법사로 전직하였습니다." << "(MP +" << MaxMp << ")" << "\n"; + GInput << "파이어볼 추가!\n"; + PlayerData.MP += MaxMp; +} + +void Mage::Release() +{ + Player::Release(); +} + +void Mage::Attack(class Monster* Target) +{ + std::string TargetName = Target->GetName(); + int TargetDefence = Target->GetDefence(); + int Damage = 0; + + Damage = (PlayerData.Attack - TargetDefence) < 0 ? 1 : (PlayerData.Attack - TargetDefence); + GInput << "파이어볼! -> " << TargetName << "에게 " << Damage << " 데미지!" << "\n"; + Target->TakeDamage(Damage); + GInput << Target->GetHP() << "\n"; + system("pause"); +} + +void Mage::TakeDamage(int Amount) +{ + Player::TakeDamage(Amount); +} \ No newline at end of file diff --git a/TextRPG/Source/Game/Characters/Player/Mage/Mage.h b/TextRPG/Source/Game/Characters/Player/Mage/Mage.h new file mode 100644 index 0000000..d5f284a --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Mage/Mage.h @@ -0,0 +1,14 @@ +#pragma once +#include "Game/Characters/Player/Player.h" + +class Mage : public Player +{ +public: + Mage(PlayerStatData&& Rvalue); + ~Mage() override; + + void Initalize() override; + void Release() override; + void Attack(class Monster* Target) override; + void TakeDamage(int Amount) override; +}; diff --git a/TextRPG/Source/Game/Characters/Player/Player.cpp b/TextRPG/Source/Game/Characters/Player/Player.cpp new file mode 100644 index 0000000..1b284c3 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Player.cpp @@ -0,0 +1,99 @@ +#include "Player.h" +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Game/Characters/Monster/Monster.h" +#include "Game/Inventory/InventorySystem.h" + +Player::Player(PlayerStatData&& Rvalue) : + PlayerData(std::move(Rvalue)), + Inventory(nullptr), + HitCount(1) +{ + OriginalData = PlayerData; + + PrepareInitInventory(); +} + +Player::~Player() +{ + Release(); +} + +void Player::PrepareInitInventory() +{ + Inventory = new InventorySystem(); +} + +void Player::Initalize() +{ + PlayerData.Level = 1; +} + +void Player::Release() +{ + SafeDelete(Inventory); +} + +void Player::PrintPlayerStatus() const +{ + GInput << "------------------------------------" << "\n"; + GInput << "닉네임: " << PlayerData.Name << " | " << "직업: " << PlayerData.Job << " | " << "Lv." << PlayerData.Level << "\n"; + GInput << "HP: " << PlayerData.HP << " | " << "MP: " << PlayerData.MP << " | " <<"공격력: " << PlayerData.Attack << " | " << "방어력: " << PlayerData.Defence << "\n"; + GInput << "------------------------------------" << "\n"; +} + +InventorySystem* Player::GetInventory() const +{ + return Inventory; +} + +std::string Player::GetName() const +{ + return PlayerData.Name; +} + +std::string Player::GetJob() const +{ + return PlayerData.Job; +} + +int Player::GetLevel() const +{ + return PlayerData.Level; +} + +int Player::GetHP() const +{ + return PlayerData.HP; +} + +int Player::GetMP() const +{ + return PlayerData.MP; +} + +int Player::GetAttack() const +{ + return PlayerData.Attack; +} + +int Player::GetDefence() const +{ + return PlayerData.Defence; +} + +void Player::TakeDamage(int Amount) +{ + int Damage = (Amount - PlayerData.Defence) < 0 ? 1 : (Amount - PlayerData.Defence); + PlayerData.HP -= Damage; +} + +bool Player::IsDead() +{ + return PlayerData.HP < 0; +} + +void Player::Reset() +{ + PlayerData = OriginalData; +} diff --git a/TextRPG/Source/Game/Characters/Player/Player.h b/TextRPG/Source/Game/Characters/Player/Player.h new file mode 100644 index 0000000..946e50a --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Player.h @@ -0,0 +1,127 @@ +#pragma once +#include "Core/Interface/Damageable.h" +#include "Core/Object/GameObject.h" + + +template +class InventorySystem; + +class Item; +class Player; + +struct PlayerStatData +{ + PlayerStatData() : + Level(0), + HP(0), + MP(0), + Attack(0), + Defence(0) + { + } + + PlayerStatData(const std::string& InName, const std::string& InJob, const int InLevel, const int InHP, const int InMP, const int InAttack, const int InDefence) : + Name(InName), + Job(InJob), + Level(InLevel), + HP(InHP), + MP(InMP), + Attack(InAttack), + Defence(InDefence) + { + } + + PlayerStatData(const PlayerStatData& Other) : + Level(0), + HP(0), + MP(0), + Attack(0), + Defence(0) + { + } + + PlayerStatData(PlayerStatData&& other) noexcept : + Name(std::move(other.Name)), + Job(std::move(other.Job)), + Level(other.Level), + HP(other.HP), + MP(other.MP), + Attack(other.Attack), + Defence(other.Defence) + { + } + + PlayerStatData& operator=(const PlayerStatData& Other) = default; + + friend std::ostream& operator<<(std::ostream& OS, const PlayerStatData& RHS); + + std::string Name; + std::string Job; + int Level; + int HP; + int MP; + int Attack; + int Defence; +}; + +inline std::ostream& operator<<(std::ostream& OS, const PlayerStatData& RHS) +{ + OS << "====================================" << "\n"; + OS << RHS.Name << " 의" << "현재 능력치" << "\n"; + OS << "====================================" << "\n"; + OS << "HP: " << RHS.HP << "\t" << "MP: " << RHS.MP << "\n"; + OS << "공격력: " << RHS.Attack << "\t" << "방어력: " << RHS.Defence << "\n"; + OS << "====================================" << "\n"; + return OS; +} + +class PlayerFactory +{ +public: + template + static Player* CreatePlayer(PlayerStatData&& Rvalue); +}; + +class Player : public GameObject, public IDamageable +{ +public: + Player() = default; + Player(PlayerStatData&& Rvalue); + ~Player() override; + + virtual void Attack(class Monster* Target) = 0; + + void Initalize() override; + void Release() override; + + void TakeDamage(int Amount) override; + bool IsDead() override; + void Reset() override; + + void PrepareInitInventory(); + void PrintPlayerStatus() const; + + InventorySystem* GetInventory() const; + + std::string GetName() const; + std::string GetJob() const; + int GetLevel() const; + int GetHP() const; + int GetMP() const; + int GetAttack() const; + int GetDefence() const; + +protected: + InventorySystem* Inventory; + PlayerStatData PlayerData; + PlayerStatData OriginalData; + int HitCount; +}; + +template +Player* PlayerFactory::CreatePlayer(PlayerStatData&& Rvalue) +{ + Player* NewPlayer = new T(std::move(Rvalue)); + NewPlayer->Initalize(); + return NewPlayer; +} diff --git a/TextRPG/Source/Game/Characters/Player/Rogue/Rogue.cpp b/TextRPG/Source/Game/Characters/Player/Rogue/Rogue.cpp new file mode 100644 index 0000000..235a4c4 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Rogue/Rogue.cpp @@ -0,0 +1,54 @@ +#include "pch.h" +#include "Rogue.h" +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Game/Characters/Monster/Monster.h" + +Rogue::Rogue(PlayerStatData&& Rvalue) : + Player(std::move(Rvalue)) +{ + HitCount = 5; +} + +Rogue::~Rogue() +{ +} + +void Rogue::Initalize() +{ + Player::Initalize(); + + PlayerData.Job = "도적"; + + int MaxHp = Game::InitCharacterJob::AddMaxHP; + GInput << "도적으로 전직하였습니다." << "(HP +" << MaxHp << ")" << "\n"; + GInput << "더블 스탭 추가!\n"; + PlayerData.Attack += MaxHp; +} + +void Rogue::Release() +{ + Player::Release(); +} + +void Rogue::Attack(class Monster* Target) +{ + std::string TargetName = Target->GetName(); + int TargetDefence = Target->GetDefence(); + int Damage = 0; + + Damage = (PlayerData.Attack - TargetDefence) < 0 ? 1 : (PlayerData.Attack - TargetDefence) / HitCount; + GInput << "더블 스탭! -> " << TargetName << "에게 " << Damage << " 데미지! (x" << HitCount << ")" << "\n"; + + GInput << Target->GetName() << " HP: " << Target->GetHP() << " -> "; + for (int i = 0; i < HitCount; ++i) + Target->TakeDamage(Damage); + + GInput << Target->GetHP() << "\n"; + system("pause"); +} + +void Rogue::TakeDamage(int Amount) +{ + Player::TakeDamage(Amount); +} \ No newline at end of file diff --git a/TextRPG/Source/Game/Characters/Player/Rogue/Rogue.h b/TextRPG/Source/Game/Characters/Player/Rogue/Rogue.h new file mode 100644 index 0000000..2af1dda --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Rogue/Rogue.h @@ -0,0 +1,14 @@ +#pragma once +#include "Game/Characters/Player/Player.h" + +class Rogue : public Player +{ +public: + Rogue(PlayerStatData&& Rvalue); + ~Rogue() override; + + void Initalize() override; + void Release() override; + void Attack(class Monster* Target) override; + void TakeDamage(int Amount) override; +}; diff --git a/TextRPG/Source/Game/Characters/Player/Warrior/Warrior.cpp b/TextRPG/Source/Game/Characters/Player/Warrior/Warrior.cpp new file mode 100644 index 0000000..e52d4eb --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Warrior/Warrior.cpp @@ -0,0 +1,51 @@ +#include "Warrior.h" +#include "GameInstance.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Game/Characters/Monster/Monster.h" + +Warrior::Warrior(PlayerStatData&& Rvalue) : + Player(std::move(Rvalue)) +{ + HitCount = 1; +} + +Warrior::~Warrior() +{ +} + +void Warrior::Initalize() +{ + Player::Initalize(); + + PlayerData.Job = "전사"; + + int MaxDefence = Game::InitCharacterJob::AddMaxDefence; + GInput << "전사로 전직하였습니다." << "(Defence +" << MaxDefence << ")" << "\n"; + GInput << "파워 스트라이크 추가!\n"; + PlayerData.Defence += MaxDefence; +} + +void Warrior::Release() +{ + Player::Release(); +} + +void Warrior::Attack(class Monster* Target) +{ + std::string TargetName = Target->GetName(); + int TargetDefence = Target->GetDefence(); + int Damage = 0; + + Damage = (PlayerData.Attack - TargetDefence) < 0 ? 1 : (PlayerData.Attack - TargetDefence); + GInput << "파워스트라이크! -> " << TargetName << "에게 " << Damage << " 데미지!" << "\n"; + GInput << Target->GetName() << " HP: " << Target->GetHP() << " -> "; + Target->TakeDamage(Damage); + GInput << Target->GetHP() << "\n"; + + system("pause"); +} + +void Warrior::TakeDamage(int Amount) +{ + Player::TakeDamage(Amount); +} \ No newline at end of file diff --git a/TextRPG/Source/Game/Characters/Player/Warrior/Warrior.h b/TextRPG/Source/Game/Characters/Player/Warrior/Warrior.h new file mode 100644 index 0000000..8678018 --- /dev/null +++ b/TextRPG/Source/Game/Characters/Player/Warrior/Warrior.h @@ -0,0 +1,14 @@ +#pragma once +#include "Game/Characters/Player/Player.h" + +class Warrior : public Player +{ +public: + Warrior(PlayerStatData&& Rvalue); + ~Warrior() override; + + void Initalize() override; + void Release() override; + void Attack(class Monster* Target) override; + void TakeDamage(int Amount) override; +}; diff --git a/TextRPG/Source/Game/Inventory/InventorySystem.cpp b/TextRPG/Source/Game/Inventory/InventorySystem.cpp new file mode 100644 index 0000000..7da97bb --- /dev/null +++ b/TextRPG/Source/Game/Inventory/InventorySystem.cpp @@ -0,0 +1 @@ +#include "InventorySystem.h" diff --git a/TextRPG/Source/Game/Inventory/InventorySystem.h b/TextRPG/Source/Game/Inventory/InventorySystem.h new file mode 100644 index 0000000..66555b2 --- /dev/null +++ b/TextRPG/Source/Game/Inventory/InventorySystem.h @@ -0,0 +1,73 @@ +#pragma once + +#include "Core/Item/Item.h" + +template +class InventorySystem +{ +public: + InventorySystem() : + Data(nullptr), + Capacity(10), + Size(0) + { + Data = new T[Capacity]; + } + + ~InventorySystem() + { + delete[] Data; + Data = nullptr; + } + + void Resize() + { + T* TempData = new T[Capacity * 2]; + for (int i = 0; i < Size;) TempData[i] = std::move(Data[i]); + + delete[] Data; + Data = TempData; + Capacity *= 2; + } + void AddItem(const T& New) + { + std::cout << "아이템 추가 시도..." << "(현재 " << Size << "/" << Capacity << ")\n"; + system("pause"); + + if (Size >= Capacity) + { + Resize(); + std::cout << "-> 인벤토리 자동 확장!\n"; + } + Data[Size++] = New; + + std::cout << "-> 아이템 추가 완료" << "(현재 " << Size << "/" << Capacity << ")\n"; + system("pause"); + + PrintAllItems(); + } + void RemoveLastItem() + { + if (Size <= 0) + Size = 0; + else + Data[Size--] = nullptr; + } + void PrintAllItems() + { + std::sort(Data, Data + Size, T::ComparePriceDesc); + + for (int i = 0; i < Size; ++i) + { + std::cout << i + 1 << ". " << Data[i].GetItemName() << " (" << Data[i].GetItemPrice() << "G) " << "\n"; + } + system("pause"); + } + int GetSize() { return Size; } + int GetCapacity() { return Capacity; } + +private: + T* Data; + int Capacity; + int Size; +}; \ No newline at end of file diff --git a/TextRPG/Source/Game/Scene/BossDungeonScene.cpp b/TextRPG/Source/Game/Scene/BossDungeonScene.cpp new file mode 100644 index 0000000..8942d94 --- /dev/null +++ b/TextRPG/Source/Game/Scene/BossDungeonScene.cpp @@ -0,0 +1,30 @@ +#include "BossDungeonScene.h" + +BossDungeonScene::BossDungeonScene(GameSceneManager* InOwner) : + CoreScene(InOwner) +{ +} + +BossDungeonScene::~BossDungeonScene() +{ +} + +void BossDungeonScene::Enter() +{ + CoreScene::Enter(); +} + +void BossDungeonScene::Update() +{ + CoreScene::Update(); +} + +void BossDungeonScene::Exit() +{ + CoreScene::Exit(); +} + +void BossDungeonScene::Release() +{ + CoreScene::Release(); +} diff --git a/TextRPG/Source/Game/Scene/BossDungeonScene.h b/TextRPG/Source/Game/Scene/BossDungeonScene.h new file mode 100644 index 0000000..a66cf1b --- /dev/null +++ b/TextRPG/Source/Game/Scene/BossDungeonScene.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Core/Scene/CoreScene.h" + +class BossDungeonScene : public CoreScene +{ +public: + BossDungeonScene(GameSceneManager* InOwner); + ~BossDungeonScene() override; + + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; +}; \ No newline at end of file diff --git a/TextRPG/Source/Game/Scene/CharacterJobScene.cpp b/TextRPG/Source/Game/Scene/CharacterJobScene.cpp new file mode 100644 index 0000000..4f68917 --- /dev/null +++ b/TextRPG/Source/Game/Scene/CharacterJobScene.cpp @@ -0,0 +1,98 @@ +#include "CharacterJobScene.h" + +#include "DungeonScene.h" +#include "GameInstance.h" +#include "MainMenuScene.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Core/Subsystems/GameDataManager.h" +#include "Core/Subsystems/SceneManager.h" +#include "Game/Characters/Player/Player.h" +#include "Game/Characters/Player/Archer/Archer.h" +#include "Game/Characters/Player/Mage/Mage.h" +#include "Game/Characters/Player/Rogue/Rogue.h" +#include "Game/Characters/Player/Warrior/Warrior.h" + +CharacterJobScene::CharacterJobScene(GameSceneManager* InOwner) : + CoreScene(InOwner) +{ + bEnableTick = true; +} + +CharacterJobScene::~CharacterJobScene() +{ +} + +void CharacterJobScene::Enter() +{ + +} + +void CharacterJobScene::Update() +{ + system("cls"); + + PlayerStatData* PlayerData = GDataMgr->GetPlayerData(); + + int SelectNum = 0; + GInput << Game::InitCharacterJob::MainMenuTitle; + GInput << PlayerData->Name << Game::InitCharacterJob::SelectJobGuide; + GInput << "1. 전사 2. 마법사 3. 도적 4. 궁수" << "\n"; + GInput << "선택: "; + + if (!(GInput >> SelectNum)) + { + GInput.Reset(); + system("pause"); + return; + } + + Player* Player = nullptr; + switch (SelectNum) + { + case 1: + { + Player = PlayerFactory::CreatePlayer(std::move(*PlayerData)); + break; + } + case 2: + { + Player = PlayerFactory::CreatePlayer(std::move(*PlayerData)); + break; + } + case 3: + { + Player = PlayerFactory::CreatePlayer(std::move(*PlayerData)); + break; + } + case 4: + { + Player = PlayerFactory::CreatePlayer(std::move(*PlayerData)); + break; + } + default: + { + GInput << Game::Common::ErrorInput; + system("pause"); + return; + } + } + + system("pause"); + + GInst->SetLocalPlayer(Player); + Player->PrintPlayerStatus(); + + system("pause"); + + Exit(); + +} + +void CharacterJobScene::Exit() +{ + Owner->TransitionTo(); +} + +void CharacterJobScene::Release() +{ +} diff --git a/TextRPG/Source/Game/Scene/CharacterJobScene.h b/TextRPG/Source/Game/Scene/CharacterJobScene.h new file mode 100644 index 0000000..5edaa01 --- /dev/null +++ b/TextRPG/Source/Game/Scene/CharacterJobScene.h @@ -0,0 +1,14 @@ +#pragma once +#include "Core/Scene/CoreScene.h" + +class CharacterJobScene : public CoreScene +{ +public: + CharacterJobScene(GameSceneManager* InOwner); + ~CharacterJobScene() override; + + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; +}; diff --git a/TextRPG/Source/Game/Scene/CharacterStatScene.cpp b/TextRPG/Source/Game/Scene/CharacterStatScene.cpp new file mode 100644 index 0000000..10806c1 --- /dev/null +++ b/TextRPG/Source/Game/Scene/CharacterStatScene.cpp @@ -0,0 +1,123 @@ +#include "pch.h" +#include "CharacterStatScene.h" + +#include "GameInstance.h" +#include "CharacterJobScene.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Core/Subsystems/GameDataManager.h" +#include "Core/Subsystems/SceneManager.h" +#include "Data/Literals/Literals.h" +#include "Game/Characters/Player/Player.h" + +CharacterStatScene::CharacterStatScene(GameSceneManager* InOwner) : + CoreScene(InOwner) +{ + bEnableTick = false; +} + +CharacterStatScene::~CharacterStatScene() +{ +} + +void CharacterStatScene::Enter() +{ + int InitHP = 5; + int InitMP = 5; + int SelectNum = 0; + bool IsGameStart = true; + + GInput << "* HP 포션 5개, MP 포션 5개가 기본 지급되었습니다." << "\n"; + + PlayerStatData* PlayerData = GInst->GetGameDataManager()->GetPlayerData(); + + while (IsGameStart) + { + GInput << "============================================" << "\n"; + GInput << "< 캐릭터 강화 >" << "\n"; + GInput << "1. HP UP 2. MP UP 3. 공격력 2배" << "\n"; + GInput << "4. 방어력 2배 5. 현재 능력치 0. 게임 시작" << "\n"; + GInput << "============================================" << "\n"; + GInput << "번호를 선택해주세요: "; + + if (!(GInput >> SelectNum)) + { + GInput.Reset(); + continue; + } + + switch (SelectNum) + { + case 0: + { + GInput << "게임을 시작합니다! \n"; + IsGameStart = false; + break; + } + case 1: + { + if (InitHP <= 0) + GInput << "HP 포션이 부족합니다. \n"; + + else + { + PlayerData->HP += 20; + --InitHP; + + GInput << "* HP가 20 증가했습니다. (HP 포션 차감: 남은 포션 " << InitHP << "개)" << "\n"; + } + break; + } + case 2: + { + if (InitMP <= 0) + GInput << "MP 포션이 부족합니다. \n"; + else + { + PlayerData->MP += 20; + --InitMP; + GInput << "* MP가 20 증가했습니다. (MP 포션 차감: 남은 포션 " << InitMP << "개)" << "\n"; + } + break; + } + case 3: + { + PlayerData->Attack *= 2; + GInput << "공격력이 현재 공격력에서 2배로 증가했습니다. (현재 공격력: " << PlayerData->Attack << ")" << "\n"; + break; + } + case 4: + { + PlayerData->Defence *= 2; + GInput << "방어력이 현재 방어력에서 2배로 증가했습니다. (현재 방어력: " << PlayerData->Defence << ")" << "\n"; + break; + } + case 5: + { + GInput << *PlayerData; + break; + } + default: + { + GInput << Game::Common::ErrorInput << "\n"; + continue; + } + } + system("pause"); + system("cls"); + } + + Exit(); +} + +void CharacterStatScene::Update() +{ +} + +void CharacterStatScene::Exit() +{ + Owner->TransitionTo(); +} + +void CharacterStatScene::Release() +{ +} diff --git a/TextRPG/Source/Game/Scene/CharacterStatScene.h b/TextRPG/Source/Game/Scene/CharacterStatScene.h new file mode 100644 index 0000000..a000ea7 --- /dev/null +++ b/TextRPG/Source/Game/Scene/CharacterStatScene.h @@ -0,0 +1,13 @@ +#pragma once +#include "Core/Scene/CoreScene.h" + +class CharacterStatScene : public CoreScene +{ +public: + CharacterStatScene(GameSceneManager* InOwner); + ~CharacterStatScene() override; + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; +}; diff --git a/TextRPG/Source/Game/Scene/CreateCharacterScene.cpp b/TextRPG/Source/Game/Scene/CreateCharacterScene.cpp new file mode 100644 index 0000000..297de2d --- /dev/null +++ b/TextRPG/Source/Game/Scene/CreateCharacterScene.cpp @@ -0,0 +1,95 @@ +#include "CreateCharacterScene.h" + +#include "GameInstance.h" +#include "CharacterStatScene.h" +#include "Core/Subsystems/SceneManager.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Core/Subsystems/GameDataManager.h" +#include "Data/Literals/Literals.h" +#include "Game/Characters/Player/Player.h" + +void PrintStatus(const std::string& Name, int Stat[]) +{ + std::cout << "====================================" << "\n"; + std::cout << Name << " 의" << "현재 능력치" << "\n"; + std::cout << "====================================" << "\n"; + std::cout << "HP: " << Stat[0] << "\t" << "MP: " << Stat[1] << "\n"; + std::cout << "공격력: " << Stat[2] << "\t" << "방어력: " << Stat[3] << "\n"; + std::cout << "====================================" << "\n"; +} + +void CreateStat(const std::string& Title, const std::string& ErrorMsg, int& Out1, int& Out2, int Max1, int Max2) +{ + while (true) + { + GInput << Title; + std::string buffer; + + if (!(GInput >> Out1 >> Out2)) + { + GInput.Reset(); + continue; + } + + bool IsValid = (Out1 < Max1 || Out2 < Max2); + if (IsValid) + { + std::cout << ErrorMsg << "\n"; + continue; + } + break; + } +} + +CreateCharacterScene::CreateCharacterScene(GameSceneManager* InOwner) : + CoreScene(InOwner) +{ + bEnableTick = false; +} + +CreateCharacterScene::~CreateCharacterScene() +{ +} + +void CreateCharacterScene::Enter() +{ + CoreScene::Enter(); + + std::string PlayerName; + const int Size = 4; + int Stat[Size] = {0}; + + GInput << "용사의 이름을 입력하세요: "; + GInput >> PlayerName; + + CreateStat(Game::CreateCharacter::SelectVitality, Game::CreateCharacter::ErrorVitality, + Stat[0], Stat[1], Game::CreateCharacter::MaxHP, Game::CreateCharacter::MaxMP); + + CreateStat(Game::CreateCharacter::SelectCombatStats, Game::CreateCharacter::ErrorCombatStats, + Stat[2], Stat[3], Game::CreateCharacter::MaxPower, Game::CreateCharacter::MaxDefence); + + auto Data = GInst->GetGameDataManager()->GetPlayerData(); + *Data = PlayerStatData(PlayerName, "", 0, Stat[0], Stat[1], Stat[2], Stat[3]); + + GInput << "\n"; + + PrintStatus(PlayerName, Stat); + system("pause"); + + Exit(); +} + +void CreateCharacterScene::Update() +{ +} + +void CreateCharacterScene::Exit() +{ + system("cls"); + Owner->TransitionTo(); +} + +void CreateCharacterScene::Release() +{ + CoreScene::Release(); +} diff --git a/TextRPG/Source/Game/Scene/CreateCharacterScene.h b/TextRPG/Source/Game/Scene/CreateCharacterScene.h new file mode 100644 index 0000000..f83c23a --- /dev/null +++ b/TextRPG/Source/Game/Scene/CreateCharacterScene.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Core/Scene/CoreScene.h" + +class CreateCharacterScene : public CoreScene +{ +public: + CreateCharacterScene(GameSceneManager* InOwner); + ~CreateCharacterScene() override; + + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; +}; \ No newline at end of file diff --git a/TextRPG/Source/Game/Scene/DungeonScene.cpp b/TextRPG/Source/Game/Scene/DungeonScene.cpp new file mode 100644 index 0000000..943a8ce --- /dev/null +++ b/TextRPG/Source/Game/Scene/DungeonScene.cpp @@ -0,0 +1,205 @@ +#include "DungeonScene.h" + +#include "BossDungeonScene.h" +#include "GameInstance.h" +#include "MainMenuScene.h" +#include "Core/Item/Item.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Core/Subsystems/SceneManager.h" +#include "Game/Characters/Monster/Monster.h" +#include "Game/Characters/Monster/Goblin/Goblin.h" +#include "Game/Characters/Monster/Orc/Orc.h" +#include "Game/Characters/Monster/Slime/Slime.h" +#include "Game/Characters/Player/Player.h" +#include "Game/Inventory/InventorySystem.h" + +DungeonScene::DungeonScene(GameSceneManager* InOwner) : + CoreScene(InOwner), + LocalPlayer(nullptr), + CurrentMonsterIndex(-1), + DungeonState(EDungeonState::Default) +{ + bEnableTick = true; + + Monster* NewSlime = new Slime(); + Monster* NewOrc = new Orc(); + Monster* NewGoblin = new Goblin(); + + Monsters.push_back(NewSlime); + Monsters.push_back(NewOrc); + Monsters.push_back(NewGoblin); +} + +EDungeonState DungeonScene::ProcessDungeonMenu() +{ + GInput << "=== DungeonRoom === \n"; + + bool IsDungeonCleared = Monsters.empty(); + size_t MaxRange = IsDungeonCleared ? 1 : Monsters.size(); + + if (!IsDungeonCleared) + { + for (size_t i = 0; i < Monsters.size(); ++i) + GInput << i + 1 << ". " << Monsters[i]->GetName() << "의 방...\n"; + } + else + { + GInput << "던전을 클리어 했습니다.\n"; + GInput << "1. 보스방 입장 \n"; + } + GInput << "0. 메인 메뉴 가기 \n"; + GInput << "선택: "; + + int Input = 0; + if (!(GInput >> Input)) + { + GInput.Reset(); + return EDungeonState::DungeonMenu; + } + + if (Input == 0) + { + return EDungeonState::DungeonExit; + } + + if (Input < 1 || Input > MaxRange) + { + GInput << Game::Common::ErrorInput; + GInput.Reset(); + return EDungeonState::DungeonMenu; + } + + if (!IsDungeonCleared) + { + CurrentMonsterIndex = Input - 1; + return EDungeonState::BattleRunning; + } + + return EDungeonState::EnterBossRoom; +} + +void DungeonScene::DestroyCurrentMonster(Monster* TargetMonster) +{ + Monsters.erase(Monsters.begin() + CurrentMonsterIndex); + SafeDelete(TargetMonster); +} + +bool DungeonScene::ProcessBattle(Monster* SelectedMonster) +{ + Player* LocalPlayer = GInst->GetLocalPlayer(); + + bool Turn = false; + while (!LocalPlayer->IsDead() && !SelectedMonster->IsDead()) + { + system("cls"); + GInput << Game::Dungeon::BattleStartTitle; + GInput << LocalPlayer->GetName() << "(" << LocalPlayer->GetJob() << ")" << " vs " << SelectedMonster->GetName() << "\n"; + system("pause"); + + if (!Turn) + { + GInput << Game::Dungeon::PlayerTurn; + LocalPlayer->Attack(SelectedMonster); + } + else + { + GInput << Game::Dungeon::TargetTurn; + SelectedMonster->Attack(LocalPlayer); + } + Turn = !Turn; + } + GInput << " (사망)" << "\n"; + + return true; +} + +void DungeonScene::EvalueteBattle(Player* TargetPlayer, Monster* TargetMonster) +{ + Player* LocalPlayer = GInst->GetLocalPlayer(); + if (TargetPlayer->IsDead()) + { + GInput << Game::Dungeon::Loose; + system("pause"); + TargetPlayer->Reset(); + + Exit(); + } + + if (TargetPlayer->IsDead()) + { + GInput << Game::Dungeon::Victory; + GInput << TargetMonster->GetDropItemName() << " 획득!\n"; + GInput << Game::Dungeon::DropItemSaveGuide; + system("pause"); + + Item Item = ItemStatData(TargetMonster->GetDropItemName(), TargetMonster->GetDropItemPrice()); + TargetPlayer->GetInventory()->AddItem(std::move(Item)); + + DestroyCurrentMonster(TargetMonster); + } +} + +void DungeonScene::Enter() +{ + CurrentMonsterIndex = -1; + DungeonState = EDungeonState::DungeonMenu; +} + +void DungeonScene::Update() +{ + switch (DungeonState) + { + case EDungeonState::DungeonMenu: + { + DungeonState = ProcessDungeonMenu(); + break; + } + case EDungeonState::BattleRunning: + { + if (ProcessBattle(Monsters[CurrentMonsterIndex])) + { + DungeonState = EDungeonState::BattleResult; + } + break; + } + case EDungeonState::BattleResult: + { + ProcessBattle(Monsters[CurrentMonsterIndex]); + break; + } + case EDungeonState::PlayerWin: + { + break; + } + case EDungeonState::PlayerLoose: + { + break; + } + case EDungeonState::DungeonReward: + { + break; + } + case EDungeonState::DungeonExit: + { + break; + } + default: assert(0); + } +} + +void DungeonScene::Exit() +{ + GInput << "메인 메뉴로 돌아갑니다." << "\n"; + system("pause"); + + Owner->TransitionTo(); +} + +void DungeonScene::Release() +{ + CoreScene::Release(); + + LocalPlayer = nullptr; + + Monsters.clear(); +} diff --git a/TextRPG/Source/Game/Scene/DungeonScene.h b/TextRPG/Source/Game/Scene/DungeonScene.h new file mode 100644 index 0000000..29ea1e2 --- /dev/null +++ b/TextRPG/Source/Game/Scene/DungeonScene.h @@ -0,0 +1,41 @@ +#pragma once + +#include "Core/Scene/CoreScene.h" +#include "Game/Characters/Player/Player.h" + +enum class EDungeonState +{ + Default = 0, + DungeonMenu, + BattleRunning, + BattleResult, + PlayerWin, + PlayerLoose, + DungeonReward, + EnterBossRoom, + DungeonExit +}; + +class Monster; +class DungeonScene : public CoreScene +{ +public: + DungeonScene(GameSceneManager* InOwner); + ~DungeonScene() override = default; + + EDungeonState ProcessDungeonMenu(); + void DestroyCurrentMonster(Monster* TargetMonster); + bool ProcessBattle(Monster* SelectedMonster); + void EvalueteBattle(Player* TargetPlayer, Monster* TargetMonster); + + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; + +private: + Player* LocalPlayer; + std::vector Monsters; + int CurrentMonsterIndex; + EDungeonState DungeonState; +}; diff --git a/TextRPG/Source/Game/Scene/InventoryScene.cpp b/TextRPG/Source/Game/Scene/InventoryScene.cpp new file mode 100644 index 0000000..454523f --- /dev/null +++ b/TextRPG/Source/Game/Scene/InventoryScene.cpp @@ -0,0 +1,42 @@ +#include "InventoryScene.h" + +#include "GameInstance.h" +#include "MainMenuScene.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Core/Subsystems/SceneManager.h" +#include "Game/Characters/Player/Player.h" +#include "Game/Inventory/InventorySystem.h" + +InventoryScene::InventoryScene(GameSceneManager* InOwner) : + CoreScene(InOwner) +{ + bEnableTick = false; +} + +InventoryScene::~InventoryScene() +{ +} + +void InventoryScene::Enter() +{ + Player* LocalPlayer = GInst->GetLocalPlayer(); + InventorySystem* Inventory = LocalPlayer->GetInventory(); + Inventory->PrintAllItems(); + system("pause"); + + Exit(); +} + +void InventoryScene::Update() +{ +} + +void InventoryScene::Exit() +{ + Owner->TransitionTo(); +} + +void InventoryScene::Release() +{ + CoreScene::Release(); +} diff --git a/TextRPG/Source/Game/Scene/InventoryScene.h b/TextRPG/Source/Game/Scene/InventoryScene.h new file mode 100644 index 0000000..a0a3c45 --- /dev/null +++ b/TextRPG/Source/Game/Scene/InventoryScene.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Core/Scene/CoreScene.h" + +class InventoryScene : public CoreScene +{ +public: + InventoryScene(GameSceneManager* InOwner); + ~InventoryScene() override; + + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; +}; \ No newline at end of file diff --git a/TextRPG/Source/Game/Scene/MainMenuScene.cpp b/TextRPG/Source/Game/Scene/MainMenuScene.cpp new file mode 100644 index 0000000..1682952 --- /dev/null +++ b/TextRPG/Source/Game/Scene/MainMenuScene.cpp @@ -0,0 +1,63 @@ +#include "MainMenuScene.h" + +#include "DungeonScene.h" +#include "GameInstance.h" +#include "PotionShopScene.h" +#include "InventoryScene.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Core/Subsystems/SceneManager.h" + +MainMenuScene::MainMenuScene(GameSceneManager* InOwner) : + CoreScene(InOwner) +{ + bEnableTick = true; +} + +MainMenuScene::~MainMenuScene() +{ +} + +void MainMenuScene::Enter() +{ +} + +void MainMenuScene::Update() +{ + int SelectNum = 0; + GInput << "=== 메인 메뉴 === \n"; + GInput << "1. 던전 입장 \n"; + GInput << "2. 인벤토리 확인 \n"; + GInput << "3. 포션 제작소 \n"; + GInput << "4. 게임 종료" << "\n"; + GInput << "선택: "; + + if (!(GInput >> SelectNum)) + { + GInput.Reset(); + return; + } + + switch (SelectNum) + { + case 1: Owner->TransitionTo(); return; + case 2: Owner->TransitionTo(); return; + case 3: Owner->TransitionTo(); return; + case 4: GInst->Quit(); return; + default: + { + GInput << Game::Common::ErrorInput; + system("pause"); + break; + } + } +} + +void MainMenuScene::Exit() +{ + CoreScene::Exit(); +} + +void MainMenuScene::Release() +{ + CoreScene::Release(); +} diff --git a/TextRPG/Source/Game/Scene/MainMenuScene.h b/TextRPG/Source/Game/Scene/MainMenuScene.h new file mode 100644 index 0000000..5041216 --- /dev/null +++ b/TextRPG/Source/Game/Scene/MainMenuScene.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Core/Scene/CoreScene.h" + +class MainMenuScene : public CoreScene +{ +public: + MainMenuScene(GameSceneManager* InOwner); + ~MainMenuScene() override; + + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; +}; \ No newline at end of file diff --git a/TextRPG/Source/Game/Scene/PotionShopScene.cpp b/TextRPG/Source/Game/Scene/PotionShopScene.cpp new file mode 100644 index 0000000..f6ee1c5 --- /dev/null +++ b/TextRPG/Source/Game/Scene/PotionShopScene.cpp @@ -0,0 +1,30 @@ +#include "PotionShopScene.h" + +PotionShopScene::PotionShopScene(GameSceneManager* InOwner) : + CoreScene(InOwner) +{ +} + +PotionShopScene::~PotionShopScene() +{ +} + +void PotionShopScene::Enter() +{ + +} + +void PotionShopScene::Update() +{ + CoreScene::Update(); +} + +void PotionShopScene::Exit() +{ + CoreScene::Exit(); +} + +void PotionShopScene::Release() +{ + CoreScene::Release(); +} diff --git a/TextRPG/Source/Game/Scene/PotionShopScene.h b/TextRPG/Source/Game/Scene/PotionShopScene.h new file mode 100644 index 0000000..a730e20 --- /dev/null +++ b/TextRPG/Source/Game/Scene/PotionShopScene.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Core/Scene/CoreScene.h" + +class PotionShopScene : public CoreScene +{ +public: + PotionShopScene(GameSceneManager* InOwner); + ~PotionShopScene() override; + + void Enter() override; + void Update() override; + void Exit() override; + void Release() override; +}; \ No newline at end of file diff --git a/TextRPG/Source/GameInstance.cpp b/TextRPG/Source/GameInstance.cpp new file mode 100644 index 0000000..63e1f99 --- /dev/null +++ b/TextRPG/Source/GameInstance.cpp @@ -0,0 +1,124 @@ +#include "GameInstance.h" + +#include "Core/Object/GameObject.h" +#include "Core/Subsystems/GameDataManager.h" +#include "Core/Subsystems/GameInputSystem.h" +#include "Core/Subsystems/SceneManager.h" +#include "Data/Literals/Literals.h" +#include "Game/Characters/Player/Player.h" +#include "Game/Scene/CharacterStatScene.h" +#include "Game/Scene/CreateCharacterScene.h" +#include "Game/Scene/DungeonScene.h" +#include "Game/Scene/CharacterJobScene.h" +#include "Game/Scene/MainMenuScene.h" +#include "Game/Scene/PotionShopScene.h" +#include "Game/Scene/InventoryScene.h" +#include "Game/Scene/BossDungeonScene.h" + +GameInstance::GameInstance() : + GameInput(nullptr), + SceneManager(nullptr), + DataManager(nullptr), + LocalPlayer(nullptr), + bIsRunning(false), + bInitalized(false) +{ + GInst = this; +} + +GameInstance::~GameInstance() +{ + Release(); +} + +void GameInstance::Run() +{ + bIsRunning = true; + GameLoop(); +} + +void GameInstance::Quit() +{ + bIsRunning = false; +} + +void GameInstance::GameLoop() +{ + Initialize(); + + while (bIsRunning) + { + Update(); + } + + std::cout << "게임 종료" << "\n"; +} + +void GameInstance::PrepareSceneManager() +{ + SceneManager = new GameSceneManager(); + SceneManager->Initialize(); + + SceneManager->CreateScenes< + CreateCharacterScene, + CharacterStatScene, + CharacterJobScene, + MainMenuScene, + DungeonScene, + PotionShopScene, + InventoryScene, + BossDungeonScene + >(); +} + +void GameInstance::PrepareCreateDataManager() +{ + DataManager = new GameDataManager(); + DataManager->Initialize(); +} + +void GameInstance::PrepareGameInput() +{ + GameInput = new GameInputSystem(); +} + +void GameInstance::Initialize() +{ + PrepareSceneManager(); + PrepareGameInput(); + PrepareCreateDataManager(); +} + +void GameInstance::PostInitialize() +{ + SceneManager->TransitionTo(); +} + +void GameInstance::Update() +{ + std::cout << Game::Common::Title; + + SceneManager->Update(); + + if (!bInitalized) + { + PostInitialize(); + bInitalized = true; + } + + system("cls"); +} + +void GameInstance::Release() +{ + for(auto It : GameObjects) + { + if (It) SafeDelete(It); + } + GameObjects.clear(); + + SafeDelete(LocalPlayer); + SafeDelete(SceneManager); + SafeDelete(DataManager); + SafeDelete(GameInput); +} diff --git a/TextRPG/Source/GameInstance.h b/TextRPG/Source/GameInstance.h new file mode 100644 index 0000000..2571c5a --- /dev/null +++ b/TextRPG/Source/GameInstance.h @@ -0,0 +1,59 @@ +#pragma once +#include "Core/Object/GameObject.h" + +class GameSceneManager; +class GameDataManager; +class GameInputSystem; +class GameObject; +class Player; +class GameInstance +{ +public: + GameInstance(); + ~GameInstance(); + + void Run(); + void Quit(); + + template + GameObject* SpawnCharacter(Arguments&&... Args); + + void PushObject(GameObject* Object) { GameObjects.push_back(Object); } + void SetLocalPlayer(Player* NewPlayer) { LocalPlayer = NewPlayer; } + + GameInputSystem* GetInput() { return GameInput; } + GameDataManager* GetGameDataManager() { return DataManager; } + Player* GetLocalPlayer() { return LocalPlayer; } + +private: + void GameLoop(); + void PrepareSceneManager(); + void PrepareCreateDataManager(); + void PrepareGameInput(); + + void Initialize(); + void PostInitialize(); + void Update(); + void Release(); + +private: + GameInputSystem* GameInput; + GameSceneManager* SceneManager; + GameDataManager* DataManager; + Player* LocalPlayer; + std::vector GameObjects; + + bool bIsRunning; + bool bInitalized; +}; + +template +inline GameObject* GameInstance::SpawnCharacter(Arguments&&... Args) +{ + static_assert(std::is_base_of_v, "반드시 Character 클래스 이거나 상속받아야 함"); + GameObject* NewCharacter = new T(std::forward(Args)...); + + GameObjects.push_back(NewCharacter); + + return NewCharacter; +} \ No newline at end of file diff --git a/TextRPG/Source/main.cpp b/TextRPG/Source/main.cpp new file mode 100644 index 0000000..6163c78 --- /dev/null +++ b/TextRPG/Source/main.cpp @@ -0,0 +1,15 @@ +#include "GameInstance.h" + +int main() +{ + GameInstance* instance = new GameInstance(); + + instance->Run(); + + SafeDelete(instance); + + std::cout << "App 종료" << "\n"; + system("pause"); + + _CrtDumpMemoryLeaks(); +} \ No newline at end of file diff --git a/TextRPG/Source/pch.cpp b/TextRPG/Source/pch.cpp new file mode 100644 index 0000000..b70460c --- /dev/null +++ b/TextRPG/Source/pch.cpp @@ -0,0 +1,3 @@ +#include "pch.h" + +GameInstance* GInst = nullptr; diff --git a/TextRPG/Source/pch.h b/TextRPG/Source/pch.h new file mode 100644 index 0000000..0c4d5eb --- /dev/null +++ b/TextRPG/Source/pch.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/CommonMemory.h" + +extern class GameInstance* GInst; + +#define GDataMgr (GInst->GetGameDataManager()) +#define GInput (*GInst->GetInput()) \ No newline at end of file diff --git a/TextRPG/TextRPG.vcxproj b/TextRPG/TextRPG.vcxproj new file mode 100644 index 0000000..4ff2f2a --- /dev/null +++ b/TextRPG/TextRPG.vcxproj @@ -0,0 +1,202 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {9beb22c7-cb82-42bd-b210-c21100fc86bf} + TextRPG + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Use + pch.h + pch.h + $(SolutionDir)TextRPG/Source + stdcpp17 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + pch.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TextRPG/TextRPG.vcxproj.filters b/TextRPG/TextRPG.vcxproj.filters new file mode 100644 index 0000000..541a926 --- /dev/null +++ b/TextRPG/TextRPG.vcxproj.filters @@ -0,0 +1,195 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + 소스 파일 + + + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + 헤더 파일 + + + \ No newline at end of file diff --git a/TextRPG/TextRPG.vcxproj.user b/TextRPG/TextRPG.vcxproj.user new file mode 100644 index 0000000..966b4ff --- /dev/null +++ b/TextRPG/TextRPG.vcxproj.user @@ -0,0 +1,6 @@ + + + + true + + \ No newline at end of file