2Bbear's knowledge workshop

Notion - UE4 언리얼 C++ 사용법 링크

작성한 글이 많아 링크로 대체합니다.

1. 개요

UE4 엔진에서 플러그인을 이용하여 손쉽게 코드를 분리하기 위해서, 모듈작업을 하는 것은 너무 불필요한 행위가 많다고 생각이 듬.

플러그인을 이용하여 코드들을 분리하여 작성하면 나중에 코드 껏다켯다만 해도 수정이 가능하니 좋다고 생각합니다.


2. 방법

  1. 프로젝트를 만듭니다. 혹은 이미 있는 프로젝트를 실행 시켜 Editor 창을 띄워도 무방합니다.

  2. Editor 창에서  상단 메뉴의 Eidt -> PlugIn을 클릭합니다.

  3. Plugin 관리 창이 뜨면 우측 하단의 New Plugin을 클릭합니다.

  4. 플러그인 생성 창에 적절히 플러그인 이름과 저작자의 이름을 등록합시다.


  5. Create Plugin을 눌르면 Visual Studio창이 켜지면서 솔루션 탐색기에 Plugin 아래에 자신이 만든 플러그인이 추가 되어 있는 것을 확인 할 수 있습니다. 추가로 Public 폴더를 열어보면   [플러그인이름BPLibrary]라고 클래스가 하나 만들어져 있는 것을 확인 할 수 있습니다.
    이제 블루프린트 관련한 코드는 저 파일에 작성하면 되는겁니다.

  6. 이제 위 사진 처럼 새로운 블루프린트 메소드를 작성해줍니다. 저는 여기서 MyTestFunction이라는 메소드를 선언했습니다.
    (추가로 UFUNTION을 작성해야지만 블루프린트로 만들어 질 수 있습니다.
    BlueprintCallable은 블루프린트로 호출 가능하다는 의미
    meta는 해당 블루프린트가 갖게 될 정보들, 예를 들어 블루프린트 이름이나, 호출 이름이나, 설명 등
    Category 해당 블루프린트가 어느 카테고리에 있을지 ,,,,나중에 Editor에서 보면 이해가 바로 됨)




  7. Hot Reload를 합시다. 이게 가장 중요함.
    다시 Editor로 돌아가서. 상단 메뉴의 Window -> Developer Tools -> Modules를 클릭.


    이러한 창이 뜨는데 상단 Search에 자신이 만든 Plugin 이름을 적어 봅시다. 그러면 하단에 자신이 만든 플러그인의 이름이 뜨고 옆에 Recompile이 나오게 됩니다. 해당 Recompile 버튼을 클릭하면 플러그인에 작성된 코드 들이 컴파일 되기 시작합니다. 
    이제 플러그인을 수정해야 할때마다 해당 버튼을 눌러야 하니 이 창을 Editor 어딘가에 붙여 둡시다.

  8. 만들어진 메소드들을 호출해 보기 , 적당히 Level 블루프린트를 열어서 우클릭을 해봅시다
    방금 자신의 플러그인에 메소드를 선언 할때 Category를 지정해 놓았다면 해당 Category이름으로 메소드가 정렬되어 있으니 적당히 이름을 검색해 봅시다.
    저 같은 경우는 Category가 Web Connect Plug in Testing 이었고, 메소드 이름이 MyTestFunction이었습니다. 
    위 사진에 올바르게 출력되는 것을 볼 수 있습니다.


끝!







추가 : 

Error - 이런 식으로 Custom Module을 만들 경우 Hot reload가 되지 않는 문제점이 발견되었다. Ue4 Ver 21

//

내가 원하는 것은 UE4 에디터 상에서 정리 가능한 C++ 코드 폴더를 만들어 내는 것이다.

이 컨텐츠 브라우저 Classes 안에 새로운 폴더를 만들고 싶은 것이다.

그렇게 하기 위해서는 모듈이라는 것을 만들어야 한다. 모듈에 대한 자세한 설명은 생략한다. 플러그인과 헷갈리지는 말자.


모듈 제작의 규칙

1. 모듈의 이름과 동일한 폴더

2. 모듈의 빌드 규칙 파일 : 모듈이름.Build.cs 로 만들어져 있어야한다.

3. 프리컴파일드 헤더와 소스파일 : 모듈이름.h , 모듈이름.cpp 로 만들어져야 한다.


모듈 제작 순서


1. 폴더를 만들어준다.

내부에 모듈 이름에 맞는 Build.cs 와 cpp, h를 만들어준다.



1-1 cpp , h, build파일에 코드를 작성한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
 
using UnrealBuildTool;
using System.Collections.Generic;
 
public class TankGameEditorTarget : TargetRules
{
    public TankGameEditorTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Editor;
        //ExtraModuleNames.Add("TankGame");
        ExtraModuleNames.AddRange(new string[] { "TankGame""TankCodes" });
    }
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
 
using UnrealBuildTool;
using System.Collections.Generic;
 
public class TankGameTarget : TargetRules
{
    public TankGameTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;
        //ExtraModuleNames.Add("TankGame");
        ExtraModuleNames.AddRange(new string[] { "TankGame","TankCodes"});
    }
}
 
cs






2. 프로젝트 target파일과 프로젝트 Editor.target.cs 파일 두곳에 모듈을 추가해 준다.


보통 프로젝트 폴더 soruce 폴더 하위에 있을 것이다....버전마다 달라질 수 있을 것 같긴한데. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//WebServerGameTank.Target.cs
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
 
using UnrealBuildTool;
using System.Collections.Generic;
 
public class WebServerGameTankTarget : TargetRules
{
    public WebServerGameTankTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;
        ExtraModuleNames.Add("WebServerGameTank");
        ExtraModuleNames.Add("TankCodes");
    }
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//WebServerGameTankEditor.Target.cs
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
 
using UnrealBuildTool;
using System.Collections.Generic;
 
public class WebServerGameTankEditorTarget : TargetRules
{
    public WebServerGameTankEditorTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Editor;
        ExtraModuleNames.Add("WebServerGameTank");
        ExtraModuleNames.Add("TankCodes");
    }
}
 
cs

d



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Fill out your copyright notice in the Description page of Project Settings.
 
using UnrealBuildTool;
 
public class TankCodes : ModuleRules
{
    public TankCodes(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
 
        PublicDependencyModuleNames.AddRange(new string[] { "Core""CoreUObject""Engine" });
 
        PrivateDependencyModuleNames.AddRange(new string[] { });
    }
}
 
cs


클래스 이름과 생성자 이름이 바뀐다는 것에 주의하자. 



3. uproject 파일을 메모장을 열어 Name과 Type을 추가한다.

연결프로그램으로 메모장을 이용하여 수정하면 되고, 이 코드를 보니 Json인거 같은데.



4. 비쥬얼 스튜디오에서 솔루션 빌드 후 에 uproject파일을 우클릭하여 Generate Visual Studio project files를 실행한다.



비쥬얼 스튜디오에 폴더가 추가되어 있음을 확인 할 수 있다. 


5. 에디터에 모듈 폴더를 추가하기 위해서, 에디터를 실행시켜 더미 클래스를 만들어준다. 

여전히 추가가 안되어 있는 상태


신기하게 모듈 선택지에 새로 추가한 모듈 이름이 보인다. 해당 이름을 선택한 뒤에 클래스를 생성하면, 5:5 확률로 실패하거나 성공할 수 있는데 이 결과에 굳이 연연하지 말자, 우리가 필요한 것은 단순히 ui로 보이는 코드가 작성되는 것이다.


만약 여기서 None class로 생성한 경우 안될 수도 있으니 AActor를 선택하여 dummy를 만들어 주자.




6. 에디터를 닫는다. 비쥬얼 스튜디오를 다시 킨 뒤 다시 솔루션 빌드(rebuild solution)를 실행시킨다.

이때는 솔루션 빌드가 성공해야한다.


7. 다시 에디터를 켜서 모듈이 추가된 것을 확인한다.





Caution!!

This document is made in unreal 4.14


---------------------------------------------------------------------------------------------------


본 정리는 

https://docs.unrealengine.com/latest/INT/API/Runtime/Core/Math/FVector/index.html


위 주소의 원문에서 정리한 내용입니다.


알면 바로 사용할 수 있는 함수들만 따로 정리했습니다.



---------------------------------------------------------------------------------------------------



FVector는 앞에 F가 붙어 있는 걸 보았을때 구조체라는 것을 알 수 있습니다.

막상 선언부를 가서 보아도 구조체라는 것을 알 수 있습니다.


FVector 는 3D 공간상에서 xyz의 컴포넌트를 가지는 구조체입니다.


-변수-

X : float

Y : float

Z : float


-Constructor- 

=> FVector 생성시 실행되는 함수들이 Override 되어 있습니다.


FVector()    초기화를 시키지 않는 생성입니다.  ex > Fvector().X=30.f;


FVector(float Inf)    모든 컴포넌트(x,y,z)를 Inf값으로 초기화 시킵니다.


FVector(const FVector4 & V)    FVector4를 이용해 xyz값을 초기화 시킵니다.


..... 중간 Constructor는 생략


FVector(const FVector2D V , float InZ)    FVector2를 이용해 x,y를 초기화 시키고 InZ를 이용

해 Z를 초기화 시킵니다.


FVector(float x, float y, float z)    x,y,z,로 xyz 컴포넌트를 각각 초기화 시킵니다.


-Function-


bool AllComponentsEqual (float Tolerance)

해당 벡터의 모든 컴포넌트(x,y,z)가 Tolerance 이상인지 판별하는 함수

=범위를 넘었는지 판별용



FVector BoundToCube(float Radius)

해당 벡터의 모든 컴포넌트를 Radius값 이하로 조절하는 함수 

=오브젝트의 최대 움직임 반경 설정


FVector ClampMaxSize(float MaxSize)

해당 벡터의 모든 컴포넌트를 Maxsize 이하로 조절한다.

사용 방법은 BoundToCube와 동일.


FVector ClampSize(float Min ,float Max)

해당벡터의 모든 컴포넌트를 Min이상 Max이하로 조절한다.


bool Coincident(const FVector & Nomal1, const FVector & Nomal2 , float ParallelCosineThreshold)

두 벡터의 방향성이 거의 ParallelCosineThreshold(오차범위) 내외로 비슷한지 판별하는 함수



bool ConstainsNaN()

해당 벡터에 x,y,z로 들어갈 수 없는 값이 들어가 있는지 확인하는 함수 

(무한대 숫자들이 걸러진다. 또는 들어가면 안되는게 들어 갔을때 걸러진다.)


float Dist(cibst FVector & V1, const FVector & V2)

두 벡터 사이의 거리를 구하는 함수


bool Equals(const FVector & V , float Tolerance)

해당 벡터가 V 벡터와 같은지 오차범위 Tolerance 안에서 반별하는 함수


bool Orthogonal(정규화 벡터 1 , 정규화 벡터 2, 오차범위)

두 정규화 벡터라고 하지만 그냥 벡터를 넣어도 무방하다. 

이 두 벡터가 직각인지 오차 범위 내에서 확인 해준다.


bool PointsAreNear(벡터 1 , 벡터 2 , 오차범위)

두 벡터가 오차범위 내로 근접해 있는지 확인해주는 함수



그 밖에


Set

ToString

ToText

가 있지만 사용하는 방법이 쉬워 생략합니다.




-Operators-

연산자들


-    마이너스 연산 가능

+    플러스 연산 가능

/    연산 가능

*    연산 가능


!=    조건 연산가능 

==    조건 연산가능

!        조건 연산가능


*=

-=

+=

/=    2항연산 가능



-Constants-


ForwardVector = (1,0,0)

RightVector = (0,1,0)

UpVector = (0,0,1)

ZeroVector = (0,0,0)


각각 FVector T.ForwardVector; 처럼 사용할 수 있다.



---------------------------------------------------------------------------------------------


1 Spawn함수나 new 연산자를 이요해서 객체를 생성하고 참조를 얻는 방법




Pseudo code


SpawnerLocating 헤더에서 MyMonster헤더를 참조하고


MyMonster의 ccp에서 SpawnerLocating의 헤더를 참조해서 각각의 클래스에서 new 또는 GetWorld()->SpawnActor 함수로 MyMonster를 참조합니다.


-----------------------------------------------------------------------------------------------


2 이미 있는 객체의 참조변수를 이용하는 방법


world 상에 이미 있는 Actor를 스포이드로 찍어서 참조하는 방법



uproperty로 변수를 노출 시키면



위 사진 처럼 스포이드를 선택 후 camera나 다른 액터를 선택해서 참조하게 하는 방법이 있습니다.































caution!!

this document is made in unreal 4.14

-------------------------------------------------------------------------------------------------------


목표


1    월드 내에 Spawner(world 상에 있는 액터)를 만들어 Monster(액터지만 world상에 없는) 를 월드에 출현 시킨다.




-------------------------------------------------------------------------------------------------------


Speudo Code



SpawnerLocating이 MyMonster을 World에 출현시킨다.


각 클래스에 있는 Mesh와 Material은 단순히 테스트 실행시 보여주기 쉽기 위해 집어 넣었을 뿐이다.


SpawnPointer라는 MyMoster형의 포인터를 생성하고 거기에 동적으로 메모리를 할당하고 그것을 월드상에 출현 시킨다.


-------------------------------------------------------------------------------------------------------


+++++++++++++++




+++++++++++++++++++++++++++++++++++++++




++++++++++++++++++++++++++++++




-------------------------------------------------------------------------------------------------------


Monster 클래스의 경우 단순한 Mesh 와 Material만 붙여 놓았기에 설명하지 않겠습니다.


-------------------------------------------------------------------------------------------------------


SpawnerLocating 클래스를 설명하겠습니다,


헤더 파일부터 살펴봅니다.


상단의 #include "MyMonster.h" 는 MyMonster 클래스 형태의 포인터를 만들기 위해 받아옵니다.


중요한 것은

#include "SpawnerLocating.generated.h" 

위에 선언을 해주어야 한다는 것입니다. generated 헤더가 가장 마지막으로 불려져야 언리얼 코드가 꼬이지 않고 실행됩니다.


AMyMonster* SpawnPointer;

몬스터형 포인터를 선언합니다. 이 후 이 포인터에 실재 몬스터를 할당해서 이후 월드에 출현시킵니다


------------------------------------------------------------------------------------------------------

/////////////////////////////////SpawnPointer

if (GetWorld() && objectState == true)

{

FActorSpawnParameters MyMonsterSpawnParam;


//Spawn Monster Naming 

FString NewActorName = "021517HowtoLocating object";

MyMonsterSpawnParam.Name = FName(*NewActorName);


//Spawn Monster Locating 

FVector SpawnLocation = GetActorLocation() + FVector(1.f, 0.f, 0.f) * 300.f;


SpawnPointer = GetWorld()->SpawnActor<AMyMonster>(SpawnLocation, FRotator(0.f), MyMonsterSpawnParam);


일단은 GetWorld로 월드가 있는지 판단하고. 저 objectState는 제가 단순히 만든 실행 bool 스위치입니다. true일경우 방금 만든 저 위의 코드들이 다 실행됩니다.


FActorSpawnParameters MyMonsterSpawnParam


FActorSpawnParameters 형의  MyMonsterSpawnParam를 선언합니다.


FActorSpawnParameters 는 액터의 파라미터가 담긴 형태입니다. 기본적인 Name 등등이 담겨있습니다.


그래서 FString으로 문자열을 만듭니다. 이 후 이 문자열은 Name으로 사용합니다.


FName형의 생성자에 방금 쓴 문자열을 넣습니다.


FVector는 벡터형을 담는 구조체입니다.


SpawnLocation이라는 벡터형에 Getworld()->SpawnActor<출현시킬 클래스액터>(벡터형 위치, 벡터형 회전,넣을 액터 파라미터)


Getworld()는 world의 메소드들을 담고 있습니다(?)


SpawnActor라는 메소드를 실행시키면 출현시킬 클래스 액터를 지정하고 매개변수로 출현 위치, 각도, 파라미터를 넣습니다.






이 포스팅들은 단순히 앞으로 언리얼을 해 나아가면서 하루 일기를 쓰듯이 써 나갑니다

덤으로 영어 공부도 해볼겸 영어로도 번역 해보니 허접하다 싶으면 댓글로 지적해주세요



caution!!

this document is made in Unreal Ver 4.14

--------------------------------------------------------------------------------------------------------------------------------


언리얼 내부에서 새로운 클래스를 만드려면 file -> 새로운 c++클래스를 눌러야합니다.

if you made New Class for c++, you must touch [File]->make New C++ Class



그 후 부모 클래스를 선택하게 되는데 

부모 클래스라 함은 앞으로 만들 클래스가 상속받을 클래스를 말합니다.

after that must choose parents class in this window

parents class is base class ,now made this class


자신이 만든 클래스 또한 이와 같이 상속을 받을 수 있습니다. 부모 클래스 선택창의 우측 상단에 있는 모든 클래스 표시를 체크 후 자신의 클래스를 찾아 상속을 받을 수 있습니다.

also made class use as a parents class. you can check this [All Class Show] box . and you found you made class   


Actor 클래스 상속 -> 월드에 배치 또는 스폰시킬때 사용하는 클래스입니다.

Actor class inherit -> this parent class is use when world spawn, placement.

Pawn 클래스 상속 -> '빙의'(카메라의 시점이 변경 되거나, 컨트롤러의 주도권이 변경되거나)하여 컨트롤러에서 

입력을 받으려고 할 때 사용하는 클래스입니다.

Pawn class inherit -> this parent class is use when you possession in game object

Character클래스 상속-> World 내에서 돌아다니는 물리법칙을 적용시키거나 움직임을 표현하려 할때 쓰입니다.

Character class inherit -> this parent class is use when you show Character motion or law of physical 




상속이 가능한 다양한 클래스들이 존재합니다만, 그중 Actor 클래스를 선택하고 Next를 누릅니다.

choose Actor class and touch the Next button.



이제 경로와 이름을 설정합니다.

다른 버튼들은 건드리지 않습니다. 그 버튼들은 아직 자세히 모릅니다.

and now write the name , file address

and do not touch another button. i don't know how to work that 


(위 사진은 Actor를 상속 받은 다른 클래스입니다.)

(this picture is Something different class that inherit Actor )


클래스를 만들면 VS(비쥬얼 스튜디오)에 


UCLASS()

class 만든 프로젝트 A클래스명 : public AActor

{

 GENERATED_BODY()


 A클래스명 //constructor 생성자


 virtual BeginPlay() override //가상함수 BeginPlay() 오버라이드


 virtual Tick()override//가상함수 Tick() 오버라이드

}


이런식으로 구성이 되어 있습니다.


When you create a class in unreal . must show up this things in VS(Visual Studio)


생성자의 경우 오버로드가 불가능합니다.(왜 인지는 모르겠습니다.)

또한 오버라이딩도 불가능합니다.(왜 인지는 모르겠습니다.)

constructor be unalbe to do overload ( i don't know why that unable)

also constructor be unalbe to do overriding


BeginePlay()는 해당 Class가 World에 출연할때 한 번만 불려지는 메소드입니다.

Tick()은 매 프레임마다 호출되어지는 메소드입니다.

BeginePlay() is when this class spawn in World , this method is calling once

Tick() is calling every frame


두 메소드 역시 오버로드가 불가능하다고 생각합니다.

그러나 오버라이딩은 가능합니다.

i'm think that these method is also unalble to do overload

but these method is can be overriding


--------------------------------------------------

생성자constructor


생성자의 내부에 보시면 PrimaryActorTick.bCanEverTick = true; 라는 문장이 있는데

이 문장은 Tick메소드가 매 프레임마다 호출되는걸 결정하는 문구입니다.

false로 두면 Tick메스드가 호출되지 않습니다.

if you see the inside of constructor. you can find [PrimaryActorTick.bCanEverTick = true; ] sentence.

this sentence is set the call Tick method each flame .

set false is not working Tick method

set true is working Tick method each flame.


생성자는 주로 Component를 이용 할 때 사용합니다.

연결시에 생성자를 이용해서 연결합니다.

constructor is use, to linking the Component



--------------------------------------------------


--------------------------------------------------

BeginPlay


BeginPlay 내부에는 Super::BeginPlay(); 라는 문구가 있습니다.

이 뜻은 현재 클래스의 부모클래스에 있는 BeginPlay() 메소드를 실행시켜라 라는 의미입니다.

결론적으로 저 문구는 AActor 클래스의 BeginPlay메소드를 실행시키게 됩니다.


보통 BeginPlay 는 현재 클래스의 초기화 작업에 이용되어집니다.

--------------------------------------------------


---------------------------------------------------

Tick


Tick의 내부에도 Super::Tick()라는 문구가 있습니다.

역시 현재 클래스의 부모 클래스인 AActor의 Tick메소드를 실행시키라는 의미입니다.


Tick은 주로 이 오브젝트의 구동에 이용되어집니다.

연산은 되도록이면 하지 않도록 합니다.

많은 시스템 자원을 잡아 먹게 됩니다.

---------------------------------------------------