#D+3 게임 엔진

겨울엔군고구마한잔·2023년 3월 6일
0

게임 엔진

목록 보기
3/5

Game Engine 개발기 +3일

목표

  • Project 형식자 지정하기
    • YAML 형식자
  • Project 파일 Load, Save하기
  • Component 분류하기
    • UUID로 분류하기

YAML

  • YAML 이란?

    YAML ain't markup lanuage라고도 불리우며,
    사람이 읽을 수도, 이해하기도 쉬운 직렬화 언어라고 생각하면 된다.
    데이터 전송 혹은 설정 파일들을 만들 때 주로 사용한다.

  • 장점

    XML과 JSON과 비교했을 때, 가장 가독성이 좋다.

  • 단점

    가독성이 좋은만큼, 단순히 사용자가 텍스트 파일 수정하듯이 바꿀 수 있다.
    이런식으로 바꾸게 될 때, 프로그램이 정상적으로 작동하지 않을 수 있다.

  • 참고 사이트

    깃허브 사이트 : https://github.com/jbeder/yaml-cpp
    공식 사이트 : https://yaml.org/

  • 프로젝트에 추가

  1. Command
mkdir OutterProject
git submodule add https://github.com/jbeder/yaml-cpp OutterProject/yaml-cpp
  1. gitmodules
    위의 Command 실행의 결과로, Command를 실행한 폴더에 생성된다.
[submodule "third-party/yaml-cpp"]
	path = third-party/yaml-cpp
	url = https://github.com/jbeder/yaml-cpp
  1. CMakeLists.txt
CMAKE_MINIMUM_REQUIRED( VERSION 3.1 )

PROJECT( Example )

ADD_SUBDIRECTORY( third-party/yaml-cpp )

ADD_EXECUTABLE( ${PROJECT_NAME} main.cpp )

INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/yaml-cpp/include )

TARGET_LINK_LIBRARIES( ${PROJECT_NAME} PRIVATE yaml-cpp)
  • 예제 1 - yaml file 불러오기

  1. 예제가 없다....
    Github에 올라와 있는 예제도 다 짤려서 있고,
    구글링을 하여도 프로젝트에 yaml-cpp를 추가하는 단계까지만 나와있다.
    그래서 나와있는 문법을 노가다하여 그냥 나름의 예제를 만들어 보았다.

  2. monsters.yaml

- name: NewName
  position: [0, 5, 0]
  powers:
    - name: Club
      damage: 10
    - name: Fist
      damage: 8
- name: Dragon
  position: [1, 0, 10]
  powers:
    - name: Fire Breath
      damage: 25
    - name: Claws
      damage: 15
- name: Wizard
  position: [5, -3, 0]
  powers:
    - name: Acid Rain
      damage: 50
  1. main.cpp
#include "yaml-cpp/yaml.h"

#include <iostream>
#include <vector>
#include <string>

int main()
{
   std::vector<Monster> MonsterData;

   // 어? 이 사람 경로 왜 이래? 라고 생각할 수 있다.
   // 내 File Tree 는
   // Project
   // - build
   //		- Debug
   // 			- Example.exe
   // - src
   // 		- main.cpp
   // monsters.yaml
   // CMakeLists.txt
   // .gitsubmodules
   // Example.exe 파일 기준으로, monsters.yaml 파일을 찾는 것이기에 이해 바란다.
   // 만약, 실행파일과 yaml 파일이 동일한 폴더내에 있으면
   // 그냥 monsters.yaml 이라고 하면 된다.
   
   YAML::Node Data = YAML::LoadFile(".\\..\\..\\monsters.yaml");
   
   while(1);
   return 0;
}
  • 예제 2 - yaml file 파일의 정보를 객체에 담기

  1. main.cpp
#include "yaml-cpp/yaml.h"
#include "yaml-cpp/Parser.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

struct VEC3
{
   float X;
   float Y;
   float Z;
};

struct Skill
{
   std::string Name;
   float Damage;
};

struct Monster
{
   std::string Name;
   VEC3 Position;
   std::vector<Skill> Powers;
};

void GetName( const YAML::Node& node, std::string& Name )
{
   // Node에서 정보를 가져올 때는 형변화를 시켜줘야 한다.
   Name = node.as<std::string>();
}

void GetPosition( const YAML::Node& node, VEC3& Vec )
{
   Vec.X = node[0].as<float>();
   Vec.Y = node[1].as<float>();
   Vec.Z = node[2].as<float>();
}

void GetDamage( const YAML::Node& node, float& Damage )
{
   Damage = node.as<float>();
}

void GetPowers( const YAML::Node& node, std::vector<Skill>& Powers )
{
   Skill TempSkill;
   for ( auto Temp : node )
   {
      GetName( Temp["name"], TempSkill.Name );
      GetDamage( Temp["damage"], TempSkill.Damage );
      Powers.push_back( TempSkill );
   }
}

int main()
{
   std::vector<Monster> MonsterData;

   YAML::Node Data = YAML::LoadFile(".\\..\\..\\monsters.yaml");

   for( auto Temp : Data )
   {
      Monster TempMonster;
      // 위의 monsters.yaml 파일을 잘 살펴보자
      // - name : NewName 
      // 이라는 부분이 있다.
      // 이러한 부분은 Key : Value로 이루어진 Map이라고 생각하면 된다.
      // std::map을 이용할 때처럼, 내가 가져오려고 하는 Value의 Key값을 입력해주면 된다.
      // 그리고, yaml은 계층구조를 가지고 있지만, 하위 계층으로 간다고 
      // 객체의 종류가 바뀌는 것이 아닌, node가 계속 연결된 형식이다.
      // 즉, Temp[~~]와 Temp[~~][~~][~~]는 종류가 같다.
      
      std::cout << "Name : " << Temp["name"] << std::endl;
      std::cout << "Position : " << Temp["position"][0] << " " << Temp["position"][1] << " " << Temp["position"][2] << " " << std::endl;

      GetName( Temp["name"], TempMonster.Name );
      GetPosition( Temp["position"], TempMonster.Position );
      GetPowers( Temp["powers"], TempMonster.Powers);

      MonsterData.push_back( TempMonster );
   }

   std::cout << " Print Data " << std::endl;
   for ( auto Temp : MonsterData )
   {
      std::cout << "Name : " << Temp.Name << std::endl;
   }

   while(1);
   return 0;
}
  • 예제 3 - yaml file 저장하기

  1. main.cpp
#include "yaml-cpp/yaml.h"
#include "yaml-cpp/Parser.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

struct VEC3
{
   float X;
   float Y;
   float Z;
};

struct Skill
{
   std::string Name;
   float Damage;
};

struct Monster
{
   std::string Name;
   VEC3 Position;
   std::vector<Skill> Powers;
};

void GetName( const YAML::Node& node, std::string& Name )
{
   Name = node.as<std::string>();
}

void GetPosition( const YAML::Node& node, VEC3& Vec )
{
   Vec.X = node[0].as<float>();
   Vec.Y = node[1].as<float>();
   Vec.Z = node[2].as<float>();
}

void GetDamage( const YAML::Node& node, float& Damage )
{
   Damage = node.as<float>();
}

void GetPowers( const YAML::Node& node, std::vector<Skill>& Powers )
{
   Skill TempSkill;
   for ( auto Temp : node )
   {
      GetName( Temp["name"], TempSkill.Name );
      GetDamage( Temp["damage"], TempSkill.Damage );
      Powers.push_back( TempSkill );
   }
}

int main()
{
   std::vector<Monster> MonsterData;

   YAML::Node Data = YAML::LoadFile(".\\..\\..\\monsters.yaml");

   for( auto Temp : Data )
   {
      Monster TempMonster;
      std::cout << "Name : " << Temp["name"] << std::endl;
      std::cout << "Position : " << Temp["position"][0] << " " << Temp["position"][1] << " " << Temp["position"][2] << " " << std::endl;

      GetName( Temp["name"], TempMonster.Name );
      GetPosition( Temp["position"], TempMonster.Position );
      GetPowers( Temp["powers"], TempMonster.Powers);

      MonsterData.push_back( TempMonster );
   }

   std::cout << " Print Data " << std::endl;
   for ( auto Temp : MonsterData )
   {
      std::cout << "Name : " << Temp.Name << std::endl;
   }

   YAML::Emitter Out;
   Out << YAML::BeginSeq;
   for ( auto Temp : MonsterData )
   {
      Out << YAML::BeginMap;
      Out << YAML::Key << "name" << YAML::Value << Temp.Name;
      Out << YAML::Key << "position";
      Out << YAML::Flow;
      Out << YAML::BeginSeq;
      Out << YAML::Value << Temp.Position.X << Temp.Position.Y << Temp.Position.Z << YAML::EndSeq;
      Out << YAML::Key << "powers";
      Out << YAML::Value;
      Out << YAML::BeginSeq;

      for ( auto Skills : Temp.Powers )
      {
         Out << YAML::BeginMap;
         Out << YAML::Key << "name" << YAML::Value << Skills.Name;
         Out << YAML::Key << "damage" << YAML::Value << Skills.Damage;
         Out << YAML::EndMap;
      }
      Out << YAML::EndSeq;

      Out << YAML::EndMap;
   }
   Out << YAML::EndSeq;

   std::ofstream fout(".\\..\\..\\Other.yaml");
   fout << Out.c_str();
   while(1);
   return 0;
}
profile
빨리 매미 소리가 크게 들리는 여름이 왔으면 좋겠다.

0개의 댓글