[Unreal]

프로젝트 세팅

럭키🍀 2021. 9. 19. 14:10

 

에픽게임즈에서 언리얼엔진탭에서 라이브러리>사용하고자 하는 엔진버전의 실행을 누르면 프로젝트 만들수 있는 창이 뜬다.

다양한 플랫폼에서 게임 눌러서 템플릿 선택(템플릿은 사실상 공부하라고 만들어 놓은 것이다?)기본을 선택하고 다음 프로젝트 세팅이다.

프로젝트 세팅 블루프린트를 선택하자. 블루프린트만으로 개발하려면 느리므로 간단하게 확인할때 주로 사용하고 나중에 C++ 코드로 바꾸고 걷어내는 식으로 해야한다. 데스크톱/콘솔선택(모바일로 선택하면 성능이슈 있을 수 있다. 물론 나중에 바꿔도 된다.), 최대 퀄리티, 시작용 콘텐츠를 포함하면 에픽에서 기본적인 메쉬들을 넣어주는건데 없음으로 하자.

언리얼은 물리기반렌더링을 엔진 렌더링의 기반으로 사용하는데 레이트레이싱은 이보다 고퀄로 렌더링해주는 방식이다. 특히 물,유리에서 반사 되는 부분에서 퀄리티 차이가 많이난다. 단점은 속도가 느리고 그랙픽카드에서 RTX이상이여야 가능하다. (배틀필드5가 사용할텐데 여기서도 옵션이다.) 비활성화 선택.

이상태에서 저장위치,이름 정해서 프로젝트 생성

 

언리얼은 오픈소스라 엔진내부코드를 보고 수정도 가능하다.

 

기본적인 에디터 구성

가운데 화면을 뷰포트라하고 위에있는 메뉴를 탭바라고 한다.

왼쪽에 액터배치. 언리얼에서 제공하는 기본적인 액터 종류들로 월드에 배치할수 있다. 뷰포트에 액터 배치 할때는 액터를 배치한다.

최상위에 UObject클래스가 있고 UActor는 UObject를 상속받는데 화면에 배치할수 있는 모든것들은 UActor를 상속받아야한다. 예) Object<-Actor<-Pawn<-Character

 

오른편에 있는 월드 아웃라이너. 월드에 배치되어있는 모든 액터들이 나타난다.

디테일패널에는 선택한 액터의 세부정보가 나타난다. 컴포넌트 추가 버튼으로 액터에 컴포넌트. 액터는 정말 월드에 배치만 가능한거고 어떤 모양을 출력하고 기능을 갖는것은 컴포넌트

컴포넌트의 종류는 크게 두가지이다. 씬컴포넌트와 액터컴포넌트. 씬컴포넌트 예) StaticMeshComponent. 에 속하면 전부 트랜스폼(위치,회전,스케일)을 갖게된다. 씬컴포넌트를 상속받은 primitive컴포넌트가 대부분 출력을 위한 목적이다.

액터컴포넌트는 트랜스폼이 없고 월드상에 배치용이 아닌 특정 기능 예)MovementComponet-특정 씬컴포넌트를 타겟으로 움직일수 있게한다. 특정기능을 수행하는 역할에 독립적으로 존재 가능하다. (씬컴포넌트는 계층적구조를 가진다..?)

아래의 콘텐츠브라우저는 현재 사용하는 여러 에셋들을 모아놓는 창이다. 콘텐츠쪽에는 에셋들, C++클래스에는 C++소스로 만든 클래스들이 보인다. 프로젝트의 콘텐트디렉토리에 있는 내용들이 나타난다. 한번 지워지면 복구가 안되므로 주의하자.

 

동작방법

카메라를 ?? 마우스 우클릭을 한 상태에서 WASD로 움직일수 있고 마우스로 우클릭상태에서 회전할수도 있다.

 

좌표계

 

당연하지만 언리얼프로젝트 만들때 한글경로 만들면 안된다.

컴파일은 C++코드를 엔진에 적용해주는 핫리로드 기능

 

 

 

제일먼저 만들어볼것은 캐릭터 만들기-플레이어 만들어서 이동하기

그 전에 월드는 여러개의 레벨로 구성될수 있다. 레벨을 하나 만들자.

 

콘텐츠에 새폴더를 만들고 이름은 Levels로 하자. 탭바에서 '현재 레벨 저장'을 누르고 만든 Levels폴더 아래에 Main이름으로 저장하자. 나중에 여러 레벨을 붙여 오픈월드를 만들수 있다. 이렇게 레벨을 먼저 저장해놓지 않으면 껐다가 다시켰을때 디폴트레벨로 켜지므로 탭바에서 '세팅'>프로젝트 세팅>맵&모드>에디터 시작 맵과 게임 기본맵을 방금만든 Main레벨로 바꿔주자.

 

캐릭터 에셋 고르기 에픽게임즈 런쳐에서 마켓플레이스에서 

전에 에픽에서만든 롤처럼 AOS인 파라곤이라는 게임의 에셋을 전부 마켓에 풀려있다. 

지원되는 엔진 버전을 확인하고 사용하자!

 

구매하고 라이브러리에 가면 보관함에 구매한 에셋들이 있다. 프로젝트추가를 눌러 가져오장.

 

 

 

<프로젝트 세팅하기>

 

<공용으로 사용할 헤더파일>

C++클래스의 프로젝트 기본 경로에 Object를 상속받아 이름은 GameInfo라고 짓는다.

(참고로 상속받을 클래스 없이 클래스를 만들으면 언리얼에서 메모리관리를 해줄수 없어서 직접적인 메모리관리를 잘 해줘야한다.)

 

GameInfo.h에서 CoreMinimal.h대신 EngineMinimal.h를 넣어준다.

#pragma once

#include "EngineMinimal.h"
#include "UObject/NoExportTypes.h"
#include "GameInfo.generated.h"

UCLASS()
class 프로젝트이름_API UGameInfo : public UObject
{
   GENERATED_BODY()
};

EngineMinimal에서 더 다양한 엔진 기능을 사용할수 있게해준다.

여기에 필요한 헤더파일들을 넣어주고 다른 클래스들은 헤더파일에서 GameInfo.h를 인클루드하면 된다.

 

C++클래스에 Player폴더를 만들고 Character를 상속받은 PlayerCharacter를 만들자.

언리얼엔진에서 플레이어나 인공지능으로 돌아가는 몬스터나 NPC는 플레이어컨트롤러나 AI컨트롤러가 있다. 플레이어 컨트롤러, AI컨트롤러는 애니메이션, 이동처리 가능하게한다.

Character는 Pawn을 상속받고 있는데 Pawn은 빙의할수 있어 즉, 조종할수 있는 특징이 있다.

 

만들어진 클래스를 보려구 VS가서 다시로드한다.

 

.cpp 폴더에서 인클루드되어있는 .h의 상위 경로는 지워주자. 

또 헤더파일에 CoreMinimal.h를 "../GameInfo.h"로 바꿔주자.

이 클래스를 빌드후에 뷰포트에 배치해보면 디테일탭에 Root Component에 충돌체인 CapsuleComponent가 있다 그리고 그 아래에 Skeletal Mesh Component가 있는데 Static Mesh와 다르게 캐릭터종류에 애니메이션을 입힐수 있게하는것이다. 앞의 두개가 Scene컴포넌트고 Actor컴포넌트로는 CharacterMovement컴포넌트가 있다.

 

위의 PlayerCharacter는 공용인것이고 각각의 플레이어마다 다른 메쉬를 가져와야하므로 새로이 클래스를 만들자.

PlayerCharacter를 상속받아 만들자 예제에선 Twinblast클래스를 만들었다.

Twinblast은 PlayerCharacter를 상속받으므로 따로 GameInfo를 포함하지 않아도된다.

 

글구  PlayerCharacter의 헤더파일과 cpp파일에서 생성자,Tick,BeginPlay,SetupPlayerInputComponent를 복사해서 붙여주자.(언리얼은 꼭 이렇게 직접만든 클래스를 상속받으면 자동으로 안만들어주더라..)

 

언리얼에서 A로 시작하면 액터종류, UObject나 컴포넌트는 U, 구조체는 F, 열거체는 앞에 E로 시작하는 네이밍을 가지고 있다.

 

언리얼에서 생성자는 뷰포트에 배치할때 한번만 호출된다. 생성자를 수정한후에 반영이이 안되면 에디터를 껐다 키면 될것이다. 그래서 BeginPlay에서는 플레이할때 한 번만 호출된다.

Tick은 매프레임 불러지면서 매 프레임간의 흐른 시간인 델타타임이 들어온다. 모든 액터들은 생성자에서 PrimaryActorTick.bCanEverTick = true;이런식으로 Tick을 사용할지 정할 수 있다.

언리얼에서는 120프레임으로 제한이 걸려있는데

SetupPlayerInputComponent는 입력처리할 때 사용하는것이다.

 

앞서 다운받은 메쉬를 SkeletalMesh에 지정하도록 불러오는 방법으로는 블루프린트로 가져오는 방법이 있고 C++코드로 가져오는 방법이 있다.

 

1.블루프린트만들기

콘텐츠에 Player폴더를 만들고 우클릭으로 블루프린트를 모든클래스>Twinblast을 상속받아 만들고 이름은 BPTwinblast으로 하자. 

블루프린트도 C++클래스라 다른 클래스를 상속받아 만든다. 

더블클릭하면 나오는 에디터에서 

메쉬를 선택하고 SkeletalMesh를 선택하기

캡슐은 가운데 중심인데 메쉬는 발 밑 중심으로 되어있다. Mesh컴포넌트는 캡슐컴포넌트의 자식으로 상대적인 값을 갖고 있는데 캡슐의 HalfHeight만큼 Mesh의 Z를 내려줘야한다.

**언리얼의 축시스템은 위아래가 Z,앞뒤가 X,좌우가 Y이다.

**좌표 1당 1cm이다.

이렇게하고 어디서 불러오지..?

 

2.C++코드로 불러오기

생성자에서

static ConstructorHelpers::FObjectFinder<USkeletalMesh> MeshAsset(TEXT())
유니코드(W_CHAR)를 언리얼에서 사용하므로 문자를 쓸때는 TEXT()로 감싸줘야한다.
레퍼런스복사해서 그 경로를 넣어준다.

 

 

 

기본으로 만들어져 있는 GameModeBase는 월드마다 하나씩 만들어지는 것이다. 게임의 규칙같은 것을 정해둘때 사용한다.

GameModeBase의 헤더도 GameInfo.h를 인클루드 하도록 CoreMinimal.h을 바꿔주고 생성자를 만들어주자.

A로 시작하는 것에서 볼 수 있듯이 액터이다. 실행을 해보면 월드에 올라와았다. 그리고 에디터에서 이 게임모드로 시작하도록 설정해준다. 프로젝트 세팅>맵&모드>Default Modes에서 기본 게임모드를 GameModeBase에서 방금 수정한 [프로젝트이름]GameModeBase로 바꿔주면된다. 이러면 실행하기를 눌렀을 때 월드아웃라이너에서 FPSGameModeBase 가 생기는 것을 볼 수 있다. A로 시작하는것에서 볼 수 있듯이 액터이므로 배치되는 것이다.

GameModeBase.cpp의 생성자에서 DefaultPawnClass를 지정해주자.

DefaultPawnClass는 실행했을 때 게임모드를 선택하면 디테일에서 볼 수 있는데 이 게임모드로 실행을 했을 때 어떤 녀석을 기본 플레이어로 지정해 시작할 것인지를 정하는 것이다. 물론 없을 수도 있다. (그런데 캐릭터를 여기서 지정한다고 해서 캐릭터가 생성되는 것은 아니다-클래스 개념이지 오브젝트 개념이 아니다.)

지정할 클래스를 include해주고 (Player/Twinblast.h파일이였다면)

#include "UE9GameModeBase.h" // 프로젝트이름GameModeBase의 클래스다.
#include "Player/Twinblast.h

AUE9GameModeBase::AUE9GameModeBase() //A로 시작하는 Actor클래스이다.
{
    // 기본 캐릭터를 불러오는 방법
    // 1.StaticClass() : 해당 클래스의 UClass 정보를 가져온다.
    // DefaultPawnClass = Twinblast::StaticClass();
    
    // 2. 블루프린트로 생성하는 방법
    // 클래스를 불러올때는 경로 뒤에 _C를 붙여준다.
    static ConstructorHelpers::FClassFinder<ACharacter>PlayerAsset(TEXT("Blueprint'/Game/Player/BPTwinblast.BPTwinblast_C'"));
	
    if (PlayerAsset.Succeeded())
        DefaultPawnClass = PlayerAsset.Class;
}

언리얼에서 제공하는 클래스는 모두들 UClass정보를 가지고 있고 이를 가져올 수 있는게 StaticClass()이다. 

DefaultPawnClass는 플레이 할 때 

 

이러면 이제 플레이를 누르면 캐릭터가 뷰포트에 배치되는 것을 볼 수 있다.(F8키를 눌러 빙의를 풀고 보자)

 

*오브젝트개념과 클래스개념

오브젝트개념은 실제 사용할 객체를 만드는것이고 클래스 개념은 그냥 해당 클래스를 사용한다는 것이다. UClass라는 개념으로 어떤 클래스를 이용해서 객체를 나중에 생성할 수 있도록 타입을 알려주는게 클래스 개념이다. 오브젝트 개념은 메쉬를 불러올때 사용해 만드는 것이므로 이때 쓰이고 클래스 개념은 DefaultPawnClass를 지정할때 쓰인다.

 

 

<카메라 세팅하기>

캡슐에 카메라 암을 달고 카메라 암에 카메라를 넣어보자.

CreateDefaultSubobject<T>(TEXT(""))로 컴포넌트를 만들수 잇다. 그런데 씬컴포넌트이므로 꼭 부모컴포넌트를 지정해줘야한다.

 

카메라암의 위치 세팅하기 트랜지션 캄포넌트를 가지고 있는데 TargetArmLength으로 거리와 TargetOffset로 높이를 조절하자. 블루프린트에서 상속관계와 값들을 확인하고 코드에 작성해보자.

 

<입력받기>

 

프로젝트세팅>입력

액션매핑 : 공격,스킬 등 누를때 눌렀다가 땔 때, 더블클릭할 때 등 인식해서 해당키가 실제로 입력됐을 때만 인식하는 것

축매핑 : 입력이 들어왔든 아니든 계속 체크하는 주로 이동 키를 눌렀을 때 사용한다.

키를 안누르면 스케일 값이 0이고 W를 누르면 1,S를 누르면 -1, 둘 다 누르면 스케일 값이 0으로 들어온다. 요게 축매핑 방법으로 매번 체크하게 되어있다.

 

그리고 SetupPlayerInputComponent에 반응할 때 어떤 함수를 부를지 함수와 매핑한 입력의 이름을 연결해 준다.

MoveFront라는 축매핑에 void MoveFront(float Scale);요런함수를 연결한다고 하면

 

축맵핑에 연결할 때 사용하려면 BindAxis를 액션매핑에 설정되어 있는 키를 설정할 때는 BindAction을 사용한다. 인자는 매핑에 설정한 이름, 객체이름, 호출할 함수 이름이다.

void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis(TEXT("MoveFront"), this, &APlayerCharacter::MoveFront);
}


void APlayerCharacter::MoveFront(float Scale)
{	
	// 루트컴포넌트(캡슐)를 움직인다.
	AddMovementInput(GetActorForwardVector(), Scale); //월드디렉션(방향)에 액터의 전방을 가져오는 벡터를 넣고 1이면 앞으로 -1이면 뒤로 움직인다.

}

이동속도은 캐릭터의 블루프린트에 CharacterMovement 컴포넌트에 세팅되어 있다. MaxWalkSpeed값으로 조절할수 있다.

 

그런데 발이 없는 것처럼 스윽 움직이니 애니메이션을 넣어보자

 

<애니메이션>