728x90

Reflection이란 쉽게 말하면 프로그램이 Runtime 중에 자료형, 변수명, 데이터 값을 가져올 수 있는 기능이다.

이 Reflection을 이용하면 작업해야하는 코드량을 줄일 수 있다.

예를 들면 구조체를 만들어서 등록하면 UI가 자동으로 생성하게한다거나, Backend에서 내려주는 데이터를 자동으로 Parsing한다거나 등등 다양하게 활용이 가능하다.

 

참고 : https://learn.microsoft.com/ko-kr/cpp/dotnet/reflection-cpp-cli?view=msvc-170

 

리플렉션(C++/CLI)

자세한 정보: 리플렉션(C++/CLI)

learn.microsoft.com

 

다른 언어에서는 언어차원에서 기본으로 제공되고 있으나, C++에서는 현재 C++차기 버전에 추가된다고 한다.

https://isocpp.org/files/papers/P2996R4.html

 

Reflection for C++26

 

isocpp.org

 

하지만, 지금 당장 사용을 해야되기 때문에 라이브러리를 여러가지 조사를 해보았다.

 

1. RTTR

- git : https://github.com/rttrorg/rttr

 

GitHub - rttrorg/rttr: C++ Reflection Library

C++ Reflection Library. Contribute to rttrorg/rttr development by creating an account on GitHub.

github.com

 

이 라이브러리를 가장 처음에 접했다. 잘만들어져있고 개발할 때 잘 사용하였으나 치명적인 약점이 있다.

이 라이브러리는 DLL로만 빌드 및 배포가 가능하기 때문에 프로그램에 RTTR을 추가하게 되면 DLL도 같이 배포를 해야만 한다.

 

2. ENTT::META

- git : https://github.com/skypjack/entt

 

GitHub - skypjack/entt: Gaming meets modern C++ - a fast and reliable entity component system (ECS) and much more

Gaming meets modern C++ - a fast and reliable entity component system (ECS) and much more - skypjack/entt

github.com

 

이 라이브러리는 Header Only이다. 즉 Header만 추가해서 사용하면 모든 기능을 사용할 수 있다.

src/entt/meta 에 있는 헤더들을 이용해서 개발하면 된다.

 

이 라이브러리는 meta로 만들어졌다가 뒤에 entt 에 포함되면서 좀더 사용이 용이하게 개량되었다.

이 라이브러리의 사용법과 굉장히 유사하지만, stl container가 추가되었고, 좀 더 사용이 편하게 개량되었다고 보면된다.

https://github.com/skypjack/meta

 

GitHub - skypjack/meta: Header-only, non-intrusive and macro-free runtime reflection system in C++

Header-only, non-intrusive and macro-free runtime reflection system in C++ - skypjack/meta

github.com

 

예제 코드

#include <entt/meta/meta.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/policy.hpp>
#include <entt/meta/container.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <memory>
#include <map>

std::map<entt::id_type, std::string> gHasheNames;
#define REGISTER_TYPE(Type)                                                                             \
    gHasheNames[entt::hashed_string(typeid(Type).name()).value()] = typeid(Type).name();                \
    entt::meta_factory<Type>().type(entt::hashed_string(typeid(Type).name()));

#define REGISTER_BASE(ChildType, ParentType)                                                            \
    entt::meta_factory<ChildType>().base<ParentType>();

// 수정: entt::as_ref_t 정책 추가
#define REGISTER_DATA(Type, Data, Name)                                                                 \
    entt::meta_factory<Type>().data<&Type::Data, entt::as_ref_t>(entt::hashed_string(Name));            \
    gHasheNames[entt::hashed_string(Name).value()] = Name;

// item 구조체 정의
struct item
{
    int price;
    std::string name;
};

// Person 구조체 정의
struct Person
{
    int age;                            // 나이 (정수)
    std::string name;                   // 이름 (문자열)
    std::vector<std::string> hobbies;   // 취미 (문자열 벡터)
    std::vector<item> items;            // 아이템 (item 구조체 벡터)

    // 생성자 추가
    Person(int age_, std::string name_, std::vector<std::string> hobbies_, std::vector<item> items_)
        : age(age_), name(name_), hobbies(hobbies_), items(items_) {}
};

// Student 구조체 정의 (Person 상속)
struct Student : public Person
{
    int grade;                          // 학년 (정수)
    std::string school;                 // 학교 (문자열)
    std::vector<std::string> subjects;  // 과목 (문자열 벡터)

    // 생성자 추가
    Student(int age_, std::string name_, std::vector<std::string> hobbies_, std::vector<item> items_,
        int grade_, std::string school_, std::vector<std::string> subjects_)
        : Person(age_, name_, hobbies_, items_), grade(grade_), school(school_), subjects(subjects_) {}
};

// Teacher 구조체 정의 (Person 상속)
struct Teacher : public Person
{
    int salary;                         // 연봉 (정수)
    std::string subject;                // 과목 (문자열)
    std::vector<std::string> students;  // 학생 (문자열 벡터)

    // 생성자 추가
    Teacher(int age_, std::string name_, std::vector<std::string> hobbies_, std::vector<item> items_,
        int salary_, std::string subject_, std::vector<std::string> students_)
        : Person(age_, name_, hobbies_, items_), salary(salary_), subject(subject_), students(students_) {}
};

int main()
{
    // 구조체를 EnTT 리플렉션 시스템에 등록
    REGISTER_TYPE(Person)
        REGISTER_DATA(Person, age, "age")
        REGISTER_DATA(Person, name, "name")
        REGISTER_DATA(Person, hobbies, "hobbies")
        REGISTER_DATA(Person, items, "items")

    REGISTER_TYPE(Student)
        REGISTER_BASE(Student, Person)
        REGISTER_DATA(Student, grade, "grade")
        REGISTER_DATA(Student, school, "school")
        REGISTER_DATA(Student, subjects, "subjects")

    REGISTER_TYPE(Teacher)
        REGISTER_BASE(Teacher, Person)
        REGISTER_DATA(Teacher, salary, "salary")
        REGISTER_DATA(Teacher, subject, "subject")
        REGISTER_DATA(Teacher, students, "students")

    // Person, Student, Teacher 객체를 포함하는 벡터 생성
    std::vector<std::unique_ptr<Person>> people;
    people.push_back(std::make_unique<Person>(30, "kim", std::vector<std::string>{ "reading", "gaming" }, std::vector<item>{ {100, "sword"}, {200, "shield"} }));
    people.push_back(std::make_unique<Student>(20, "lee", std::vector<std::string>{ "studying" }, std::vector<item>{}, 3, "harvard", std::vector<std::string>{ "physics", "chemistry" }));
    people.push_back(std::make_unique<Teacher>(40, "park", std::vector<std::string>{ "teaching" }, std::vector<item>{}, 2000000, "math", std::vector<std::string>{ "alice", "bob" }));

    // 각 객체의 모든 멤버를 출력하고 수정
    for (auto& person_ptr : people)
    {
        // 객체를 meta_handle로 래핑하여 실제 타입 유지
        entt::meta_handle meta_handle(person_ptr.get());

        // 객체의 런타임 타입 가져오기
        auto meta_type = meta_handle.type();

        std::cout << "Type: " << meta_type.info().name() << std::endl;

        // 모든 데이터 멤버 순회
        for (auto member : meta_type.data())
        {
            // 멤버 이름 가져오기
            std::string member_name = gHasheNames[member.first];
            auto value = member.second.get(meta_handle);

            // 타입별로 처리
            if (value.type().id() == entt::resolve<int>().id()) {
                int val = value.cast<int>();
                std::cout << member_name << ": " << val << std::endl;
                // 수정: 1 증가
                member.second.set(meta_handle, entt::meta_any{ val + 1 });
                std::cout << "Modified " << member_name << ": " << member.second.get(meta_handle).cast<int>() << std::endl;
            }
            else if (value.type().id() == entt::resolve<std::string>().id()) {
                std::string val = value.cast<std::string>();
                std::cout << member_name << ": " << val << std::endl;
                // 수정: "_modified" 추가
                auto& str_ref = value.cast<std::string&>();
                str_ref += "_modified";
                std::cout << "Modified " << member_name << ": " << member.second.get(meta_handle).cast<std::string>() << std::endl;
            }
            else if (value.type().id() == entt::resolve<std::vector<std::string>>().id()) {
                auto vec_str = value.cast<std::vector<std::string>>();
                std::cout << member_name << ": ";
                for (const auto& str : vec_str) std::cout << str << " ";
                std::cout << std::endl;
                // 수정: "new_element" 추가
                auto& vec_ref = value.cast<std::vector<std::string>&>();
                vec_ref.push_back("new_element");
                std::cout << "Modified " << member_name << ": ";
                for (const auto& str : member.second.get(meta_handle).cast<std::vector<std::string>>()) std::cout << str << " ";
                std::cout << std::endl;
            }
            else if (value.type().id() == entt::resolve<std::vector<item>>().id()) {
                auto vec_item = value.cast<std::vector<item>>();
                std::cout << member_name << ": ";
                for (const auto& it : vec_item) std::cout << it.name << "(" << it.price << ") ";
                std::cout << std::endl;
                // 수정: 새로운 아이템 추가
                auto& vec_ref = value.cast<std::vector<item>&>();
                vec_ref.push_back({ 300, "new_item" });
                std::cout << "Modified " << member_name << ": ";
                for (const auto& it : member.second.get(meta_handle).cast<std::vector<item>>()) std::cout << it.name << "(" << it.price << ") ";
                std::cout << std::endl;
            }
            else {
                std::cout << member_name << ": Unknown type" << std::endl;
            }
        }
        std::cout << "-----" << std::endl;
    }

    return 0;
}

 

 

 

 

728x90

'Basic Programming > C, C++' 카테고리의 다른 글

C/C++ - 정적 초기화 순서 실패  (0) 2025.04.13
C/C++ - QueueUserAPC  (0) 2023.04.20
C/C++ - Interrupt 감지  (0) 2023.04.07
C/C++ - push_macro()  (0) 2022.10.12
C/C++ - vcpkg에서 MT, MD 변경 방법  (0) 2022.02.17
728x90
:-----------------------------------------------------------------------------------------------------------------------------
REM Check administrator privileges
REM ref : https://bebhionn.tistory.com/52
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"

REM If error flag is set, we don't have admin rights
if '%errorlevel%' NEQ '0' (goto UACPrompt) else ( goto gotAdmin )

:UACPrompt
    echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
    set params = %*:"=""
    echo UAC.ShellExecute "cmd.exe", "/c %~s0 %params%", "", "runas", 1 >> "%temp%\getadmin.vbs"

    "%temp%\getadmin.vbs"
    del "%temp%\getadmin.vbs"
    exit /B

:gotAdmin
    REM When running with admin rights, default path changes, so change it to bat file path (%~dp0)
    CD /D "%~dp0"
:-----------------------------------------------------------------------------------------------------------------------------

참고 : https://bebhionn.tistory.com/52

 

Batch 파일 관리자 권한으로 실행 코드

batch 파일을 만들때 오른쪽 -> 관리자 권한으로 실행 으로 안하고 바로 실행해도 관리자 권한을 얻어오고 싶을 때 사용하는 코드입니다. 제일 앞에 기입해야 하며 @echo off가 있을 시 @echo off 뒤에

bebhionn.tistory.com

 

728x90

'Script > bat' 카테고리의 다른 글

Bat - MSBuild/VsDevCmd의 경로를 가져오기.  (0) 2025.04.13
728x90

CI/CD를 동작시킬 때 MSBuild를 사용하는 경우가 있을 것이다.

이 때 개발환경과 CI/CD환경이 다를 것이고 경로도 다를 것이다.

그래서 Build.bat 파일과 같이 bat파일로 동작시키는 경우가 있다.

 

MSBuild의 경로 가져오기

:-----------------------------------------------------------------------------------------------------------------------------
REM Find Visual Studio 2022 installation
set MSBUILD_PATH=

REM Try to find Visual Studio installation using vswhere
set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do (
    set "MSBUILD_PATH=%%i\MSBuild\Current\Bin\MSBuild.exe"
    goto :found_msbuild
)

:found_msbuild
if "%MSBUILD_PATH%"=="" (
    echo Error: MSBuild.exe not found.
    echo Please install Visual Studio 2022 and try again.
    pause
    exit /B 1
)
:-----------------------------------------------------------------------------------------------------------------------------

:-----------------------------------------------------------------------------------------------------------------------------
echo Using MSBuild at: %MSBUILD_PATH%

REM "%MSBUILD_PATH%" Engine.sln -p:Configuration="Debug" -p:Platform=Win32
REM "%MSBUILD_PATH%" Engine.sln -p:Configuration="Release" -p:Platform=Win32

"%MSBUILD_PATH%" Engine.sln -p:Configuration="Debug" -p:Platform=x64
REM "%MSBUILD_PATH%" Engine.sln -p:Configuration="Release" -p:Platform=x64
:-----------------------------------------------------------------------------------------------------------------------------

 

VsDevCmd의 경로 가져오기

나의 경우에는 Visual Studio 2022를 사용하고 있기 때문에 VS2022_PATH라고 했을 뿐이다.

이렇게하면 설치된 최신 버전의 Visual Studio 의 VsDevCmd.bat 경로를 가져올 것이다.

:-----------------------------------------------------------------------------------------------------------------------------
echo.
echo [Execute VsDevCmd.bat]
REM Find Visual Studio 2022 installation
set VS2022_PATH=

REM Try to find Visual Studio installation using vswhere
set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
for /f "usebackq tokens=*" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do (
    set "VS2022_PATH=%%i\Common7\Tools\VsDevCmd.bat"
    goto :found_vs
)

:found_vs
if "%VS2022_PATH%"=="" (
    echo Error: Visual Studio 2022 not found.
    echo Please install Visual Studio 2022 and try again.
    pause
    exit /B 1
)

echo Using Visual Studio 2022 at: %VS2022_PATH%
call "%VS2022_PATH%"
:-----------------------------------------------------------------------------------------------------------------------------
728x90

'Script > bat' 카테고리의 다른 글

Bat - 관리자 권한으로 실행하기  (0) 2025.04.13
728x90

전역 변수를 만들어놓았지만, 전역 변수가 초기화 되기 전에 사용되면서 크래시가 발생하는 경우가 있다.

이것을 Static Initialization Order Fiasco(정적 초기화 순서 실패, 정적 초기화 순서 재앙) 이라고 불린다.

참고 : https://en.cppreference.com/w/cpp/language/siof

 

Static Initialization Order Fiasco - cppreference.com

The static initialization order fiasco refers to the ambiguity in the order that objects with static storage duration in different translation units are initialized in. If an object in one translation unit relies on an object in another translation unit al

en.cppreference.com

 

예를 들어 아래와 같이 NamePool이라는 전역 객체가 있을 때 FName 객체의 생성자를 호출했을 때 NamePool 객체가 생성이 되지 않은 상태에서 NamePool에 데이터를 넣으려다가 크래시가 발생할 수 있다.

std::unordered_map<uint64, FString> NamePool;

FName::FName(FStringView InString)
{
    FString String = InString.data();
    HashCode = Hash(String.data());
    NamePool[HashCode] = String; // <- 여기서 Crash
}

FName::FName(const WIDECHAR* InString)
	:FName(FStringView(InString))
{
}

FString FName::ToString() const
{
    FString Out;
    ToString(Out);
    return Out;
}

void FName::ToString(FString& Out) const
{
    if (HashCode == 0)
    {
        return;
    }

    Out = NamePool[HashCode];
}

 

이를 방지하기 위해선 아래와 같이 코드를 수정하면 된다.

std::unordered_map<uint64, FString>& GetNamePool() // <- 이 함수가 중요
{
    static std::unordered_map<uint64, FString> NamePool;
    return NamePool;
}

FName::FName(FStringView InString)
{
    FString String = InString.data();
    HashCode = Hash(String.data());
    GetNamePool()[HashCode] = String;
}

FName::FName(const WIDECHAR* InString)
	:FName(FStringView(InString))
{
}

FString FName::ToString() const
{
    FString Out;
    ToString(Out);
    return Out;
}


void FName::ToString(FString& Out) const
{
    if (HashCode == 0)
    {
        return;
    }

    Out = GetNamePool()[HashCode];
}

 

이 방법을 "Construct on First Use" 아이디엄 이라고 부른다.

참고 : https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Construct_On_First_Use

 

More C++ Idioms/Construct On First Use - Wikibooks, open books for an open world

From Wikibooks, open books for an open world Ensure that an object is initialized before its first use. Specifically, ensure that non-local static object is initialized before its first use. Lazy construction/evaluation Static objects that have non-trivial

en.wikibooks.org

 

728x90

'Basic Programming > C, C++' 카테고리의 다른 글

C/C++ - Reflection Library (RTTR, ENTT::META)  (0) 2025.04.13
C/C++ - QueueUserAPC  (0) 2023.04.20
C/C++ - Interrupt 감지  (0) 2023.04.07
C/C++ - push_macro()  (0) 2022.10.12
C/C++ - vcpkg에서 MT, MD 변경 방법  (0) 2022.02.17
728x90

1.웹뷰2의 환경 설정 및 기본 샘플 빌드 방법

 

Get started with WebView2 in Win32 apps - Microsoft Edge Developer documentation

Get started building WebView2 for Win32 by working with sample apps and the WebView2 SDK.

learn.microsoft.com

 

2.위 샘플에서 WebView2에 대한 소스 코드

// <-- WebView2 sample code starts here -->
// Step 3 - Create a single WebView within the parent window
// Locate the browser and set up the environment for WebView
CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,
    Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
        [hWnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT 
        {
            // Create a CoreWebView2Controller and 
            // get the associated CoreWebView2 whose parent is the main window hWnd
            env->CreateCoreWebView2Controller(
                hWnd, 
                Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
                [hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT 
                {
                    if (controller != nullptr) 
                    {
                        webviewController = controller;
                        webviewController->get_CoreWebView2(&webview);
                    }
                    
                    // Add a few settings for the webview
                    // The demo step is redundant since the values are the default settings
                    wil::com_ptr<ICoreWebView2Settings> settings;
                    webview->get_Settings(&settings);
                    settings->put_IsScriptEnabled(TRUE);
                    settings->put_AreDefaultScriptDialogsEnabled(TRUE);
                    settings->put_IsWebMessageEnabled(TRUE);
                    
                    // Resize WebView to fit the bounds of the parent window
                    RECT bounds;
                    GetClientRect(hWnd, &bounds);
                    webviewController->put_Bounds(bounds);

                    // Schedule an async task to navigate to Bing
                    webview->Navigate(L"https://www.bing.com/");

                    return S_OK;
                }).Get());
            return S_OK;
        }).Get());

 

WebView2의 코드는 Callback 기반으로 동작한다.

 

// Step 4 - Navigation events
// register an ICoreWebView2NavigationStartingEventHandler to cancel any non-https navigation
EventRegistrationToken token;
webview->add_NavigationStarting(Callback<ICoreWebView2NavigationStartingEventHandler>(
    [](ICoreWebView2* webview, ICoreWebView2NavigationStartingEventArgs* args) -> HRESULT 
    {
        wil::unique_cotaskmem_string uri;
        args->get_Uri(&uri);
        std::wstring source(uri.get());
        if (source.substr(0, 5) != L"https") 
        {
            args->put_Cancel(true);
        }
        return S_OK;
    }).Get(), &token);
  • Navigate할 때 이벤트를 등록할 수 있다
  • 위에 코드는 Navigation을 시작할 때 uri가 https 가 아니면 사이트를 열지 않겠다는 이벤트를 등록한다

 

// Step 5 - Scripting
// Schedule an async task to add initialization script that freezes the Object object
webview->AddScriptToExecuteOnDocumentCreated(L"Object.freeze(Object);", nullptr);
// Schedule an async task to get the document URL
webview->ExecuteScript(L"window.document.URL;", Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
    [](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT 
    {
        LPCWSTR URL = resultObjectAsJson;
        //doSomethingWithURL(URL);
        return S_OK;
    }).Get());
  • WebView2 컨트롤에 JavaScript 코드를 삽입할 수 있다
  • 삽입된 JavaScript는 JavaScript가 제거될 때까지 모든 새로운 최상위 문서와 모든 하위 프레임에 적용된다

 

// Step 6 - Communication between host and web content
// Set an event handler for the host to return received message back to the web content
webview->add_WebMessageReceived(Callback<ICoreWebView2WebMessageReceivedEventHandler>(
    [](ICoreWebView2* webview, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT 
    {
        wil::unique_cotaskmem_string message;
        args->TryGetWebMessageAsString(&message);
        // processMessage(&message);
        webview->PostWebMessageAsString(message.get());
        return S_OK;
    }).Get(), &token);

// Schedule an async task to add initialization script that
// 1) Add an listener to print message from the host
// 2) Post document URL to the host
webview->AddScriptToExecuteOnDocumentCreated(
    L"window.chrome.webview.addEventListener(\'message\', event => alert(event.data));" \
    L"window.chrome.webview.postMessage(window.document.URL);",
    nullptr);
  • 호스트와 웹 콘텐츠의 통신도 가능하다 (postMessage)
  • Web -> Host
    • WebView2 컨트롤 내에서 실행되는 웹 콘텐츠는 메서드를 통해 호스트에 게실될 수 있으며 window.chrome.webview.postMessage는 호스트에 등록된 ICoreWebView2WebMessageReceivedEventHandler 이벤트 핸들러에 의해 처리된다
  • Host -> Web
    • ICoreWebView2::PostWebMessageAsString
    • ICoreWebView2::PostWebMessageAsJSON
    • 위 메서드를 통해 웹 콘텐츠에 메시지를 보낼 수 있으며 이 메시지는 리스너에 추가된 핸들러에 의해 포착된다
    • window.chrome.webview.addEventListener 이 통신 메커니즘을 사용하면 호스트에 기본 API를 실행하도록 요청하는 메시지를 전달하여 웹 콘텐츠가 기본 기능을 사용할 수 있다
  • 메커니즘을 이해하기 위한 예로 WebView2에서 문서 URL을 출력하려고하면 다음 단계가 발생한다
    • 호스트는 수신된 메시지를 웹 콘텐츠로 다시 반환하기 위한 핸들러를 등록합니다.
    • 호스트는 호스트에서 메시지를 인쇄하기 위해 핸들러를 등록하는 스크립트를 웹 콘텐츠에 삽입합니다.
    • 호스트는 호스트에 URL을 게시하는 웹 콘텐츠에 스크립트를 삽입합니다.
    • 호스트의 핸들러가 트리거되어 메시지(URL)를 웹 콘텐츠에 반환합니다.
    • 웹 콘텐츠의 핸들러가 트리거되고 호스트(URL)의 메시지를 인쇄합니다.
728x90

'Basic Programming > WebView2' 카테고리의 다른 글

WebView2 - 참고 사이트들  (0) 2024.05.19
728x90
728x90

'Basic Programming > WebView2' 카테고리의 다른 글

WebView2 - WebView2GettingStarted 코드 분석  (0) 2024.05.19
728x90
728x90

'Game Programming > Unity' 카테고리의 다른 글

Unity - SendMessage, BroadcastMessage, SendMessageUpwards  (0) 2017.06.12
Unity - OSVR 연동하기  (0) 2017.05.29
Unity - 단축키  (0) 2017.05.24
Unity - Logitech Extream 3D Pro 키 세팅  (0) 2017.05.23
Unity - 캐릭터 점프하기  (0) 2017.05.22
728x90

1. Epic Games Launcher 설치

EpicGames 홈페이지에서 Epic Games Launcher를 다운로드 받는다.

https://store.epicgames.com/en-US/

 

2. Unreal Engine 설치

Epic Games Launcher -> 라이브러리 -> 엔전 설치

 

언리얼 설치 후에 옵션에서 "디버깅을 위한 편집기 기호"를 추가적으로 설치하는 것을 추천한다. 
언리얼의 디버깅을 하려면 필요하다.

3. Visual Studio 2022 Community 설치

https://visualstudio.microsoft.com/ko/vs/community/ 에서 다운로드 후 설치

 

4. Visual Studio Installer를 이용해서 2022 필요한 기능 설치

아래 이미지에서 C++을 사용한 데스크톱 개발과 C++을 사용한 게임 개발 2개만 설치하면 된다.
나머지는 다른 것들을 개발하다보니 설치를 했다.

언어팩에서 영어 설치
언리얼 관련해서 인터넷 검색을 해보면 영어로된 자료가 더 많이 나오기 때문에 그냥 Visual Studio 2022의 설정을 영어로 하는 것을 추천한다.

 

5. 언리얼 세팅

Visual Studio 버전이 여러개가 설치되어있을 때 명시적으로 Visual Studio 2022의 버전을 지정해줘야한다.
여기에서 설정되면 모든 언리얼 프로젝트에 공통으로 적용된다.

 

 6. Visual Studio 2022 환경 세팅

옵션 -> 국가별 설정 -> 영어

 

옵션 -> 프로젝트 & 솔루션 -> Always show Error List if build finisheds with errors 체크 해제

 

Tools -> Customize -> Solution Configurations 의 길이 변경 (65 -> 200)

 

7. Visual Studio 2022 Extensions

아래와 같이 GENERATED_BODY() 매크로가 있는 상태에서 Enter Key를 누르면 들여쓰기가 되는데, 개발 중에 계속 들여쓰기가 되면 불편하기 때문에 확장 기능을 추가한다.

https://vlasovstudio.com/visual-commander/ 여기서 다운로드해서 설치하자.

그리고 https://github.com/hackalyze/ue4-vs-extensions 에서 다운로드하고 압축을 풀면 ue4_smarter_macro_indenting_vs2017-2019.vcmd 이런 파일이 있는데 이 파일을 2022에서도 쓸수있다.

Extensions -> Vcmd -> import -> ue4_smarter_macro_indenting_vs2017-2019.vcmd 하면 된다.

이후에 설치를 확인하고 싶으면 Extensions -> Vcmd -> Extensions 를 하면 아래와 같이 체크된 것을 확인할 수 있다.

728x90

'Game Programming > Unreal' 카테고리의 다른 글

Unreal5 문서  (0) 2023.09.17
Unreal - Unreal 4 Document  (0) 2016.12.02

+ Recent posts