캐릭터 애니메이션 설정

Unreal 이론|2024. 10. 21. 19:35

[이득우의 언리얼 프로그래밍 Part2 수업의 정리]

 

스켈레톤과 AnimInstance를 같이 선택해준다.

static ConstructorHelpers::FObjectFinder<USkeletalMesh> CharacterMeshRef(TEXT("/Script/Engine.SkeletalMesh'/Game/InfinityBladeWarriors/Character/CompleteCharacters/SK_CharM_Cardboard.SK_CharM_Cardboard'"));
if (CharacterMeshRef.Object) {
	GetMesh()->SetSkeletalMesh(CharacterMeshRef.Object);
}
static ConstructorHelpers::FClassFinder<UAnimInstance> AnimInstanceClassRef(TEXT("/Game/ArenaBattle/Animation/ABP_AB_Character.ABP_AB_Character_C"));
if (AnimInstanceClassRef.Class) {
	GetMesh()->SetAnimInstanceClass(AnimInstanceClassRef.Class);
}

 

ConstructorHelper를 사용해 원하는 캐릭터 메시를 입혀주고 캐릭터 애니메이션 인스턴스도 지정해준다.

 

캐릭터 애니메이션 시스템의 생성

  • 스켈레탈 메시 컴포넌트의 애니메이션 블루프린트 클래스를 지정한다.
  • 캐릭터가 초기화될때 AnimInstance 클래스의 인스턴스를 생성한다
  • 캐릭터는 GetAnimInstance 함수를 사용해 애니메이션 인스턴스를 얻을 수 있음
  • 애니메이션 인스턴스는 GetOwningActor 함수를 사용해 자신을 소유한 액터 정보를 얻을 수 있음

 

캐릭터 애니메이션 시스템의 설계

  • 애니메이션 블루프린트는 이벤트 그래프와 애님 그래프 두 영역으로 구성
  • 이벤트 그래프에서는 이벤트로부터 상태를 파악할 수 있는 주요 변수를 저장하는데 사용
  • 애님 그래프에서는 저장된 변수로부터 지정된 상태의 애니메이션 재생
  • 애님 그래프의 복잡한 상태는 State Alias로 분리해 효과적으로 설계 가능
  • Initialize -> 처음 시작때, Update-> 프레임 마다 (둘다 발생시 GetOwning 이벤트 발생해 현재 캐릭터 상황 살펴보고 상태를 내가 지정한 변수에 저장)
  • 그 상태를 보고 애님 그래프에서 애니메이션 재생

'Unreal 이론' 카테고리의 다른 글

캐릭터 컨트롤 설정  (0) 2024.10.20
캐릭터와 입력 시스템  (1) 2024.10.19
언리얼 엔진 게임 제작 기초  (0) 2024.10.14
언리얼 빌드 시스템  (1) 2024.10.03
언리얼 오브젝트 관리 - 패키지  (0) 2024.10.01

댓글()

캐릭터 컨트롤 설정

Unreal 이론|2024. 10. 20. 14:38

[이득우의 언리얼 프로그래밍 Part2 수업의 정리]

 

캐릭터 컨트롤

  • 일반적으로 컨트롤러와 폰, 카메라, 스프링암, 캐릭터 무브먼트의 다섯가지 요소를 사용해 설정
    • 컨트롤러: 입력자의 의지(목표지점)을 지정할 때 사용. ControlRotation 속성
    • 폰: 폰의 트랜스폼을 지정
    • 카메라: 화면 구도를 설정하기 위해 사용. 주로 1인칭 시점에서 사용
    • 스프링 암: 화면 구도를 설정하기 위해 사용. 주로 3인칭 시점에서 사용
    • 캐릭터 무브먼트: 캐릭터의 이동과 회전을 조정하는 용도로 사용

폰의 이동 함수

  • Look 함수: 마우스 입력으로부터 컨트롤러의 컨트롤 회전을 설정
  • Move 함수: 컨트롤러의 컨트롤 회전으로부터 Yaw 값을 참고해 이동 방향을 설정
  • 콘솔 커맨드 창(단축키~) 으로부터 Control Rotation값을 확인할 수 있음
    • "DisplayAll PlayerController ControlRotation"
void AABCharacterPlayer::Move(const FInputActionValue& Value)
{
	FVector2D MovementVector = Value.Get<FVector2D>();

	const FRotator Rotation = Controller->GetControlRotation();
	const FRotator YawRotation(0, Rotation.Yaw, 0);

	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

	AddMovementInput(ForwardDirection, MovementVector.X);
	AddMovementInput(RightDirection, MovementVector.Y);
}

void AABCharacterPlayer::Look(const FInputActionValue& Value)
{
	FVector2D LookAxisVector = Value.Get<FVector2D>();

	AddControllerYawInput(LookAxisVector.X);
	AddControllerPitchInput(LookAxisVector.Y);
}

 

폰의 컨트롤 옵션

  • Use Controller Rotation (Yaw/Roll/Pitch)
  • 컨트롤러에 지정된 Control Rotation 값에 폰의 Rotation을 맞출 것인가?
  • 이 옵션을 키면 폰의 회전은 컨트롤러의 Control Rotation과 동기화됨
  • Desired Rotation = Control Rotation -> 일정 속도로 회전하는 것이 아닌 즉시 동기화

스프링암의 컨트롤 옵션

  • Use Pawn Control Rotation
  • Inherit (Yaw/Roll/Pitch)
  • Do Collision Test
  • 폰의 컨트롤 회전 (컨트롤러의 Control Rotation) 을 사용할 것인가?
  • 부모 컴포넌트 (주로 RootComponent) 의 회전을 그대로 따를 것인가?
  • 스프링암 중간에 장애물이 있으면 앞으로 당길 것인가? (Camera라는 트레이스 채널을 사용)
  • 3인칭 시점 설정에 주로 사용

마우스가 움직일 때 SpringArm이 같이 움직인다
장애물이 폰과 카메라 사이에 생겼을 때 카메라를 당겨주는 Do Collision Test

 

카메라의 컨트롤 옵션

  • Use Pawn Control Rotation
  • 폰의 컨트롤 회전 (컨트롤러의 Control Rotation) 을 사용할 것인가?
  • 스프링암에 달려있다면 스프링암의 회전과 함께 고려
  • 1인칭 카메라 회전에 주로 사용

 

캐릭터 무브먼트의 이동 옵션

  • Movement Mode : None, Walking, Falling
  • 땅(Ground) 위에 있으면 Walking 모드
  • 땅 위에 없으면 Falling 모드
  • 이동 기능을 끄고 싶으면 None 모드
  • 이동 모드에서의 이동 수치: MaxWalkSpeed
  • 폴링 모드에서의 점프 수치: JumpZVelocity

 

캐릭터 무브먼트의 회전 옵션

  • Rotation Rate: 회전 속도의 지정
  • Use Controller Desired Rotation : 컨트롤 회전을 목표 회전으로 삼고 지정한 속도로 돌리기
  • Orient Rotation To Movement : 캐릭터 이동 방향에 회전을 일치시키기
  • 폰의 회전 옵션과 충돌이 나지 않도록 주의

 

데이터 에셋

  • UDataAsset을 상속받은 언리얼 오브젝트 클래스
  • 에디터에서 에셋 형태로 편리하게 데이터를 관리할 수 있음
  • 캐릭터 컨트롤에 관련된 주요 옵션을 모아 에셋으로 관리

 

데이터 에셋의 관리

  • 두 가지의 컨트롤 모드를 제공
    • 현재 구현된 컨트롤 모드 : 3인칭 숄더뷰
    • 추가로 구현할 컨트롤 모드 : 3인칭 쿼터뷰
  • 입력키 v를 통해 컨트롤 설정을 변경 (배그에서도 v키로 1인칭<ㅡ>3인칭 변경이 가능했었다)
  • ENUM을 통해 두 개의 컨트롤 데이터를 관리

컨트롤 관리자라는 자료구조에서 두개의 에셋 데이터를 포함해서 관리

 

데이터 에셋의 구성과 적용

  • 각 섹션별로 데이터를 저장
    • Pawn 카테고리
    • 캐릭터 무브먼트 카테고리
    • 입력 카테고리
    • 스프링암 카테고리
  • Pawn과 캐릭터 무브먼트 데이터는 CharacterBase에서 설정
  • 입력과 스프링암 데이터는 CharacterPlayer에서 설정

 

뷰의 변환

  • 컨트롤을 변경할 때 서로 다른 입력 매핑 컨텍스트를 지정
  • 숄더뷰 : ShoulderMove와 ShoulderLook 사용
  • 쿼터뷰: QuaterMove만 사용 (마우스 회전에 따른 시점 이동 없기 때문)
  • 입력 액션 - V키를 사용해 변경

'Unreal 이론' 카테고리의 다른 글

캐릭터 애니메이션 설정  (0) 2024.10.21
캐릭터와 입력 시스템  (1) 2024.10.19
언리얼 엔진 게임 제작 기초  (0) 2024.10.14
언리얼 빌드 시스템  (1) 2024.10.03
언리얼 오브젝트 관리 - 패키지  (0) 2024.10.01

댓글()

캐릭터와 입력 시스템

Unreal 이론|2024. 10. 19. 23:16

[이득우의 언리얼 프로그래밍 Part2 수업의 정리]

 

액터의 구조

  • 월드에 속한 컨텐츠의 기본 단위 - 액터
  • 액터는 트랜스폼을 가지며, 월드로부터 틱과 시간서비스를 제공받는다
  • 사실 액터는 논리적 개념. 컴포넌트를 감싸는 포장 박스에 불과함
  • 실질적 구현은 컴포넌트가 진행하며 액터는 다수의 컴포넌트 소유하고 있음
  • 다수의 컴포넌트를 대표하는 컴포넌트를 루트 컴포넌트(Root Component)라고 함
  • 액터는 루트 컴포넌트를 가져야 하며, 루트 컴포넌트의 트랜스폼은 액터의 트랜스폼을 의미한다.

DefaultSceneRoot는 임시로 생성한 아무 기능 없는 컴포넌트

 

C++ 액터에서 컴포넌트의 생성

  • 컴포넌트는 언리얼 오브젝트이므로 UPROPERTY를 설정하고 TObjectPtr로 포인터를 선언
    • 언리얼5버전부터 헤더에 언리얼 오브젝트를 선언할 때 일반 포인터에서 TObjectPtr로 변경
  • 컴포넌트의 등록
    • CDO(Class Default Object - 생성자)에서 생성한 컴포넌트는 자동으로 월드에 등록된다.
    • NewObject로 생성한 컴포넌트는 반드시 등록절차를 거쳐야한다.(예: RegisterComponent)
    • 등록된 컴포넌트만이 월드의 기능을 사용할 수 있으며, 물리와 렌더링 처리에 합류한다.
  • 컴포넌트의 확장 설계
    • 에디터 편집 및 블루프린트로의 승계를 위한 설정
    • UPROPERTY에 지정자(Specifier)를 설정할 수 있다.
  • 컴포넌트 지정자
    • Visible / Edit : 크게 객체타입과 값타입으로 사용
    • Anywhere / DefaultsOnly / InstanceOnly : 에디터에서 편집 가능 영역
    • BlueprintReadOnly / BlueprintReadWrite : 블루프린트로 확장시 읽기 혹은 읽기쓰기 권한을 부여
    • Category: 에디터 편집 영역(Detail)에서의 카테고리 지정
  • C++로 최대한 만들어 놓은 후 블루프린트에서 최소한만 추가해서 액터를 생성하는것이 필요
  • 블루프린트에서 Static Mesh에다가 Mesh를 입혀 만들수도 있지만, 아래처럼 C++에서 어느정도 틀을 만들수도 있다.
AABFountain::AABFountain()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	Body = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Body"));
	Water = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Water"));

	RootComponent = Body;
	Water->SetupAttachment(Body);
	Water->SetRelativeLocation(FVector(0.0f, 0.0f, 132.0f));

	static ConstructorHelpers::FObjectFinder<UStaticMesh> BodyMeshRef(TEXT("/Game/ArenaBattle/Environment/Props/SM_Plains_Castle_Fountain_01.SM_Plains_Castle_Fountain_01"));
	if (BodyMeshRef.Object) {
		Body->SetStaticMesh(BodyMeshRef.Object);
	}

	static ConstructorHelpers::FObjectFinder<UStaticMesh> WaterMeshRef(TEXT("/Game/ArenaBattle/Environment/Props/SM_Plains_Fountain_02.SM_Plains_Fountain_02"));
	if (WaterMeshRef.Object) {
		Water->SetStaticMesh(WaterMeshRef.Object);
	}
}

ClassSetting에서 Parent Class를 C++로 만들어놓은 액터로 설정한 후 라이팅만 추가

 

폰의 기능과 설계

  • 폰은 액터를 상속받은 특별한 액터이며, 플레이어가 빙의해 입출력을 처리하도록 설계되어 있음
  • 폰에 카메라를 부착하면 폰이 바라보는 세상이 플레이어 화면에 출력됨
  • 입력을 지정하면 폰에 입력이 전달되어 플레이어가 폰을 움직이도록 조종할 수 있게됨
  • 폰은 길찾기를 사용할 수 있으며, 일반적으로 세 가지 주요 컴포넌트로 구성된다.
    • 기믹과 상호작용을 담당하는 충돌 컴포넌트 (루트컴포넌트)
    • 시각적인 비주얼을 담당하는 메시 컴포넌트
    • 움직임을 담당하는 컴포넌트
  • 컴포넌트 중에서 트랜스폼이 없이 기능만 제공하는 컴포넌트를 액터컴포넌트라고 한다.
  • 트랜스폼이 있는 컴포넌트 = 씬 컴포넌트

 

캐릭터의 기본구조

  • 캐릭터는 인간형 폰을 구성하도록 언리얼이 제공하는 전문 폰 클래스를 의미
  • 캐릭터는 세가지 주요 컴포넌트로 구성됨
    • 기믹과 상호작용을 담당하는 캡슐 컴포넌트(루트 컴포넌트)
    • 애니메이션 캐릭터를 표현하는 스켈레탈 메시 컴포넌트
    • 캐릭터의 움직임을 담당하는 캐릭터 무브먼트(CharacterMovement) 컴포넌트

Character의 정의로 이동해보면 이미 private으로 세가지 컴포넌트가 선언되있는걸 확인 가능

 

입력 시스템의 동작 방식

  • 플레이어의 입력은 컨트롤러를 통해 폰으로 전달됨
  • 입력을 컨트롤러가 처리할 수도, 폰이 처리할 수도 있는데, 일반적으론 폰이 처리하도록 설정
    • ex) GTA같은 다양한 사물에 빙의하는 게임의 경우 폰이 유리 (GTA는 사람, 자동차, 헬기, 오토바이 등등 다양한 사물에 빙의)

향상된 입력시스템(Enhanced Input System)

  • 기존 입력시스템을 대체하고 언리얼 5.1부터 새롭게 도입
  • 사용자의 입력 설정 변경에 유연하게 대처할 수 있도록 구조를 재수립
  • 사용자 입력 처리를 네 단계로 세분화하고 각 설정을 독립적인 애셋으로 대체

향상된 입력시스템 동작 구성

  • 사용자의 입력 데이터를 최종 함수에 매핑하는 과정을 체계적으로 구성
  • 플랫폼에 따른 다양한 입력 장치의 설정
    • 예) 게임패드용 입력 매핑 컨텍스트, 키보드용 입력 매핑 컨텍스트
  • 입력 값의 변경
    • 예) AD/WS 입력값을 Y축과 X축으로 변경, 값 반전의 처리
  • 이벤트 발생 조건의 상세 설정
    • 예) 일반 버튼인가? 축 이동인가? 일정 이상 눌러야 하는가?

 

'Unreal 이론' 카테고리의 다른 글

캐릭터 애니메이션 설정  (0) 2024.10.21
캐릭터 컨트롤 설정  (0) 2024.10.20
언리얼 엔진 게임 제작 기초  (0) 2024.10.14
언리얼 빌드 시스템  (1) 2024.10.03
언리얼 오브젝트 관리 - 패키지  (0) 2024.10.01

댓글()

언리얼 엔진 게임 제작 기초

Unreal 이론|2024. 10. 14. 16:54

[이득우의 언리얼 프로그래밍 Part2 수업의 정리]

 

게임 컨텐츠의 구조

  • 게임 제작을 위해 언리얼 엔진은 자체적으로 설계한 프레임웍을 제공함
  • 이를 게임플레이 프레임웍(Gameplay Framework) 라고 부름.
  • 언리얼 게임 프레임웍의 각 구성 요소를 파악하고, 이를 확장하면서 게임 제작 권장

게임 컨텐츠의 구성요소를 체계적으로 정리한 모습

월드

  • 게임 컨텐츠를 담기 위해 제공되는 가상의 공간
  • 월드는 시간, 트랜스폼, 틱을 서비스로 제공
  • 월드 세팅이라는 컨텐츠 제작을 위한 기본 환경 설정을 제공
  • 월드의 기본 단위는 액터(Actor)로 정의, 액터 클래스는 언제나 접두사 A 사용
  • 월드의 역할
    • 게임 컨텐츠를 담는 공간(Transform)
    • 게임 컨텐츠의 진행(Tick)
    • 게임 흐름을 위한 시간(Time)
    • 기본 환경 설정(World Setting)
    • 월드의 단위 구성 요소(Actor)

게임 모드

  • 게임 규칙을 지정하고 게임을 판정하는 최고 관리자 액터. 형태는 없음
  • 언리얼 엔진에서 하나의 게임에는 반드시 하나의 게임모드만 존재한다.
  • 게임 모드에서 입장할 사용자의 규격을 지정할 수 있음
  • 멀티플레이어 게임에서 판정을 처리하는 절대적 권위의 심판
  • 게임모드의 역할
    • 플레이어 입장 관리
    • 게임의 최종 승패 관리
    • 게임의 규칙 관리
    • 게임 데이터 검증(멀티플레이 게임)

기믹(Gimmick)

  • 게임 진행을 위한 이벤트를 발생시키는 사물 액터
  • 주로 이벤트 발생을 위한 충돌 영역을 설정하는데, 이를 트리거(Trigger) 라고 한다.
  • 트리거를 통해 캐릭터와 상호 작용하고, 월드에 액터를 스폰해 컨텐츠를 전개한다.
  • 기믹의 역할
    • 월드 내 사물과 상호작용 수행
    • 지정된 조건 만족시 이벤트 발생
    • 월드에 물체를 스폰(Spawn) 시킬 수 있음

플레이어

  • 게임에 입장한 사용자 액터. 형태 없다.
  • 게임 모드의 로그인을 통해 사용자가 게임 월드에 입장하면 플레이어가 생성
  • 싱글 플레이 게임에서는 0번이라는 특수한 ID의 플레이어가 설정됨
  • 사용자와의 최종 커뮤니케이션 담당 (입력 장치의 해석, 화면 장치로의 출력 등)
  • 플레이어의 역할
    • 게임에 입장한 사용자와의 1:1 대응
    • 사용자의 현재 상태 및 데이터를 관리
    • 사용자 입력의 1차 처리(필요시)
    • 사용자 화면에 대응하는 카메라 관리
    • 사용자 화면에 나타나는 HUD UI 관리

폰(Pawn)

  • 무형의 액터인 플레이어가 빙의해 조종하는 액터
  • 길찾기 사용할 수 있으며, 기믹 및 다른 폰과 상호작용한다.
  • 폰 중에서 인간형 폰을 별도로 캐릭터라고 지칭한다.
  • 폰의 역할
    • 빙의(Possess)를 통해 플레이어와 연결
    • 사용자 입력의 실제 처리
    • 사용자 화면에 대응되는 카메라 설정
    • 기믹과의 상호작용
    • 현재 상태에 적합한 애니메이션 재생

게임의 제작 과정

  • 이번 과정의 싱글플레이 게임 제작은 크게 다섯단계
  • 1단계: 월드 설정과 게임 모드 생성
  • 2단계: 플레이어 폰의 입출력 및 모션 설정(언리얼 엔진이 제공하는 삼인칭 템플릿 활용)
  • 3단계: 캐릭터에 반응하는 기믹 설계
  • 4단계: 게임데이터와 NPC 인공지능
  • 5단계: UI 연동 및 게임 제작 마무리\

최종 확장 내용

  • 기본 템플릿 사용x, 직접 제작
  • 두가지 카메라 모드 제공 (솔더뷰, 탑뷰)
  • 액션 입력을 통한 콤보 공격 구현
  • 아이템 에셋을 활용한 무기 상자의 구현
  • NPC 레벨 정보를 스프레드 시트로 관리
  • 플레이어와 전투하는 NPC 인공지능의 구현
  • UI연동과 게임의 마무리

프로젝트 생성

  • C++ Blank 템플릿으로 생성
  • 프로젝트 이름은 ArenaBattle
    • 주 게임 모듈 이름은 이렇게 하면 자동으로 ArenaBattle로 지정됨.

프로젝트 소스코드 폴더 규칙

  • 게임플레이를 구성하는 요소별로 폴더 제작해 관리
    • Game: 게임 모드와 게임 설정에 관련된 클래스
    • Gimmick: 기믹 배경 물체에 관련된 클래스
    • Player: 플레이어에 관련된 클래스
    • Input: 플레이어 입력에 관련된 클래스
    • Character: 플레이어 입력에 관련된 클래스
    • Action: 캐릭터 액션에 관련된 클래스
    • Item: 캐릭터 아이템에 관련된 클래스
    • Stat: 캐릭터 스탯에 관련된 클래스
    • AI: NPC 인공지능에 관련된 클래스
    • UI: UI에 관련된 클래스
    • Physics: 물리 충돌체 설정에 관련된 전처리기
    • Interface: 인터페이스 클래스를 모아둔 폴더

클래스 생성 규칙

  • 모든 클래스는 AB의 접두사로 시작
  • 폴더마다 다른 폴더와의 의존성 최소화
  • 다른 폴더의 클래스에 접근할 때 가급적 인터페이스를 통해 접근
  • 헤더 경로를 찾기 쉽도록 모듈.Build.cs 파일에 모듈의 폴더를 인클루드 경로에 설정
    • PublicIncludePath.AddRange( new String[] {"Module_Name"}); 추가
  • 가급적 다른 폴더의 헤더 직접 참조하지 않도록 구성하는 것이 바람직

최초 생성 클래스

  • 게임 구성하는 기본 골격의 설정
  • 캐릭터는 PC와 NPC 구분해 구현
  • 게임 모드에서는 입장할 플레이어의 규격 지정 (AABPlayerController, AABCharacterPlayer)

 

최초 생성 클래스들을 폴더 규칙에 맞춰 생성

 

이후 작업 내용

  • Content Browser에서 Add 버튼으로 Thirdperson 템플릿을 추가함
  • ABGameMode 클래스를 World settings에서 GameMode Override에 설정해준다.
    • ABGameMode 클래스에 생성자를 만들어준다.
    • Dafault Pawn Class는 BP_ThirdPersonCharacter의 Reference를 ConstructorHelper 함수를 통해 가져와서 지정해준다.
    • Player Pawn Class는 include를 통해 옆 폴더의 헤더파일을 가져와서 PlayerControllerClass = AABPlayerController::StaticClass(); 로 지정해줘도 되지만, 폴더간 의존성을 줄이기 위해 DefaultPawnClass 처럼 ref를 가져와 지정해준다.
// ABGameMode.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "ABGameMode.generated.h"

/**
 * 
 */
UCLASS()
class ARENABATTLE_API AABGameMode : public AGameModeBase
{
	GENERATED_BODY()

public:
	AABGameMode();
	
};
// ABGameMode.cpp


#include "Game/ABGameMode.h"

AABGameMode::AABGameMode()
{
	static ConstructorHelpers::FClassFinder<APawn> ThirdPersonClassRef(TEXT("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter.BP_ThirdPersonCharacter_C"));
	if (ThirdPersonClassRef.Class) {
		DefaultPawnClass = ThirdPersonClassRef.Class;
	}
	// DefaultPawnClass
	static ConstructorHelpers::FClassFinder<APlayerController> PlayerControllerClassRef(TEXT("/Script/ArenaBattle.ABPlayerController"));
	if (PlayerControllerClassRef.Class) {
		PlayerControllerClass = PlayerControllerClassRef.Class;
	}
	//PlayerControllerClass = AABPlayerController::StaticClass();
}
  • ABPlayerController에는 게임을 시작하자마자 마우스 포인터가 뷰포트 안으로 들어가도록 설정해준다.
    • BeginPlay 함수를 상속받아 내부에 구현한다.
// ABPlayerController.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "ABPlayerController.generated.h"

/**
 * 
 */
UCLASS()
class ARENABATTLE_API AABPlayerController : public APlayerController
{
	GENERATED_BODY()

protected:
	virtual void BeginPlay() override;
	
};

 

// ABPlayerController.cpp

#include "Player/ABPlayerController.h"

void AABPlayerController::BeginPlay()
{
	Super::BeginPlay();

	FInputModeGameOnly GameOnlyInputMode;
	SetInputMode(GameOnlyInputMode);
}

'Unreal 이론' 카테고리의 다른 글

캐릭터 컨트롤 설정  (0) 2024.10.20
캐릭터와 입력 시스템  (1) 2024.10.19
언리얼 빌드 시스템  (1) 2024.10.03
언리얼 오브젝트 관리 - 패키지  (0) 2024.10.01
언리얼 오브젝트 관리 - 직렬화  (0) 2024.09.12

댓글()

C++ LNK2005, LNK2001 에러

Error|2024. 10. 7. 18:47

GameMode 파일에서 클라이언트에서 멀티플레이 세션을 생성하도록 프로그래밍을 했었다.

하지만 GameMode파일을 캐스팅 해서 블루프린트로 가져오고, 내부의 CreateSession 함수를 호출하는 과정에서 게임모드 파일이 캐스팅 되지 않는 문제가 발생했다.

위의 문제의 원인은 GameMode 파일을 클라이언트 부분에서 건드릴수 없었기 때문이었고, 결국 playercontroller 클래스를 하나 생성해 클라이언트가 해당 클래스를 통해 서버로 세션 생성을 요청 보낼수 있도록 구조를 변경하기로 하였다.

 

그리고 클라이언트의 요청-> Gamemode의 세션 생성 함수 호출-> Gamemode 클래스에서 세션 생성 이 세 단계를 거치기 위해 함수를 생성했다.

 

자세한건 개발 일지에 적겠지만, 이 과정에서 서버와 클라이언트 함수엔 implementation과 validate 함수가 생략되어선 안됬는데 Implementation 함수는 위와 같이 구현부와 상관없는 부분이라 생각해 생략했고, validate 함수는 당장 요청을 검토하는 로직을 구현할건 아니기 때문에 생략했다.

 

꼭 들어가야 하는 부분이 생략되어 위와 같은 에러가 발생했고, 구현부는 Implementation 부분에, Validate 부분은 일단 True만 리턴하도록 만들어 놓으니 에러가 사라졌다.

 

꼭 위와 같은 케이스가 아니더라도 cpp 함수 부분에서 중복 선언을 했거나 전처리를 중복으로 선언하는 등의 상황에서 해당 에러가 발생하니 눈 똑바로 뜨고 잘 확인해보자.

'Error' 카테고리의 다른 글

ModRSsim Key 오류, MSVCR100.dll 오류  (0) 2023.08.28
응용프로그램의 side-by-side  (0) 2023.08.25

댓글()

언리얼 빌드 시스템

Unreal 이론|2024. 10. 3. 18:08

[이득우의 언리얼 프로그래밍 수업의 정리]

 

언리얼 에디터 구성

  • 게임 제작을 위해 에픽 게임즈가 제공하는 저작 도구
  • 언리얼 엔진의 구성
    • 에디터: 게임 제작을 위해 제공되는 응용 프로그램(일반적으로 인식하는 언리얼 엔진)
    • 게임 빌드: EXE 파일과 리소스로 이루어진 독립적으로 동작하는 게임 클라이언트
  • 언리얼 에디터의 특징
    • 게임 개발 작업을 위해 다양한 폴더와 파일 이름 규칙이 미리 설정되있다.
    • 정해진 규칙을 잘 파악하고 프로젝트 폴더와 파일을 설정해야함.
  • 에디터에서 기획과 개발을 완료한 후, 게임 빌드를 통해 최종 게임 빌드를 제작하도록 설정
  • 에디터에서 게임 구성 -> 게임 빌드 수행 후 프로그램 패키징

언리얼 에디터의 동작

  • 프로젝트 폴더의 uproject 확장자를 더블클릭하면 에디터 트리거됨
  • 에디터 실행방식
    • uproject 확장자는 윈도우 레지스트리에 등록되어있음
      • 만약 등록x -> 런처 실행해 등록
    • UnrealVersionSelector 프로그램으로 프로젝트 정보 넘겨짐
    • UnrealVersionSelector는 런처가 저장한 에디터 정보로부터 버전에 맞는 에디터 실행
  • UnrealVersionSelector 소스는 에픽게임즈 깃헙에서 확인 가능
  • .uproject -> UnrealVersionSelector -> UnrealEditor 구조로 동작

에디터 버전 정보 파악

  • 프로젝트.uproject 텍스트 파일에 정해져 있음
  • .uproject 확장자는 에디터를 띄우기 위한 명세서 역할
  • 버전 내용은 JSON 형식으로 구성되어 있음 -> 멀티플레이어 게임 만든다고 프로젝트 옮길때 에디터 버전 변경하면서 썻던 그 JSON
  • 파일에 기록된 버전 정보를 바탕으로 에픽 런처가 지정한 정보를 찾아 에디터를 실행함.
    • ProgramData/Epic/UnrealLauncher 폴더에 관련 정보 있음
    • 이 역시 JSON 형식으로 설치된 언리얼 버전 정보가 기록되어 있음

블루프린트 프로젝트

  • C++ 코드가 없는 언리얼 프로젝트를 의미
  • 언리얼 엔진이 제공하는 기본 기능을 활용해 게임을 제작하는 프로젝트
  • 언리얼 엔진은 게임 제작에 필요한 기능을 모듈이라는 단위로 제공
  • 언리얼 엔진의 모듈을 상속받아 블루프린트를 활용해 모든 기능과 로직 구현하는 방식

언리얼 C++ 프로젝트

  • 언리얼 엔진 C++ 모듈에 개발자가 추가로 자신만의 C++ 모듈을 추가할 수 있음
  • 언리얼 엔진 모듈과 개발자 모듈을 함께 사용하는 프로젝트

언리얼 C++ 모듈

  • 언리얼 엔진의 소스코드는 모두 모듈 단위로 구성되어 있음
  • 모듈을 컴파일 함으로써 에디터 및 게임에 우리가 제작한 로직을 공급할 수 있음
  • 모듈 단위로 구성된 C++ 소스 코드를 컴파일 한 결과물
    • 에디터용: DLL 동적 라이브러리
    • 게임용: 정적 라이브러리
  • 에디터용 모듈은 언제나 UnrealEditor-{모듈 이름}.DLL 이름 규칙 가지고 있음

언리얼 C++ 모듈 추가

  • 기본 언리얼 모듈에 우리가 제작한 C++ 모듈을 추가해 에디터를 띄우고 싶은 경우
  • 우리가 만든 에디터 모듈(DLL 동적라이브러리)을 빌드 폴더에 넣어주어야 함
    • Windows 경우 Binaries/Win64 폴더에 해당 DLL 넣어야 함
    • 빌드된 모듈 목록이 있는 UnrealEditor.modules 파일도 같은 폴더에 넣어주어야 인식됨.
  • uproject 명세서에 모듈 이름 지정하고 에디터 실행

이런 느낌

모듈 C++ 코드의 관리

  • 언리얼 프로젝트가 소스 코드를 관리하는 규칙에 따라 소스 코드 구조를 구성해야함
  • 소스 코드는 멀티 플랫폼 빌드 시스템을 지원하기 위해 특정 프로그램에 종속되있지 않음
  • 실제 빌드를 진행하는 주체: Unreal Build Tool 이라는 C# 프로그램
  • Source 폴더에 지정된 규칙대로 소스를 넣으면 플랫폼에 맞춰서 알아서 컴파일을 진행

Source 폴더의 구조

  • 타겟 설정 파일
  • 모듈 폴더(보통 프로젝트 이름으로 모듈 이름 지정)
    • 모듈 설정 파일
    • 소스 코드 파일(헤더파일, cpp 파일)
  • 타겟 설정 파일: 전체 솔루션이 다룰 빌드 대상 지정
    • {프로젝트이름}.Target.cs: 게임 빌드 설정
    • {프로젝트이름}Editor.Target.cs: 에디터 빌드 설정
  • 모듈 설정 파일: 모듈을 빌드하기 위한 C++ 프로젝트 설정 정보
    • {모듈이름}.Build.cs: 모듈을 빌드하기 위한 환경 설정
  • C#이 가진 유연한 기능(compile on-the-fly)을 활용해 런타임에 cs 파일을 읽어 빌드 환경 구축하고 컴파일 진행

게임 프로젝트의 소스

  • 내가 만든 소스가 게임 프로젝트의 C++ 모듈이 되기 위해 필요한 것
  • 모듈(Module)을 구현한 선언한 헤더와 소스파일이 있어야 함
    • 주로 {모듈이름}.h와 {모듈이름}.cpp로 지정
  • 모듈의 뼈대 제작
    • 매크로를 통해 기본 뼈대 구조를 제작
      • IMPLEMENT_MODULE: 일반 모듈 (게임과 직접적 연관x, 유용한 기능 제공해주는 C++ 코드 라이브러리)
      • IMPLEMENT_GAME_MODULE: 게임 모듈 (게임 제작에 관련된 모듈)
      • IMPLEMENT_PRIMARY_GAME_MODULE: 주 게임 모듈 (게임을 제작하는데 있어 가장 중심이 되는, 게임이 동작하는데 사용되는 로직 모아둔 모듈)
  • 일반적으로 게임 프로젝트는 주 게임 모듈을 하나 선언해야함
  • 모든 준비가 완료되면 Generate Visual Studio project file. 메뉴를 선택
  • Intermediate 폴더에 프로젝트 관련 파일이 자동으로 생성됨
  • Source폴더를 규칙에 맞게 구성하면 Intermediate 폴더는 언제든지 재생성 가능

모듈간의 종속 관계

  • 모듈 사이에 종속 관계를 설정해 다양한 기능을 구현할 수 있다.
  • 우리가 만드는 게임 모듈도 언리얼 엔진이 만든 모듈을 활용해야 한다.
  • 언리얼 엔진이 제공하는 모듈 사이에도 종속 관계 있음

새로운 모듈 추가

  • 하나의 모듈에 너무 많은 코드 들어가면 언리얼 엔진은 빌드 방식 변경
  • 프로젝트가 커질수록 모듈 나눠서 관리하는게 유리

모듈의 공개와 참조

  • 모듈 내 소스를 필요한 만큼만 공개해야 모듈 간 의존성 줄이고 컴파일타임 최소화 할 수 있음
  • 딱 필요한 부분에 대해서만 참조 (의존성 줄여야 변경사항에 유연한 대처 및 컴파일 타임 최소화) 
  • 공개할 파일은 모두 Public  폴더로 (예전 UE는 Classes 폴더가 Public 폴더 역할)
  • 숨길 파일은 모두 Private 폴더로
  • 외부로 공개할 클래스 선언에는 {모듈이름}_DLL 매크로 붙일 것
  • 게임 모듈에서는 Build.cs 설정을 통해 참조할 모듈 지정할 수 있음

플러그인 시스템

  • 게임 프로젝트 소스에 모듈을 추가하는 방법은 분업 어렵다는 단점 존재
  • 모듈만 독립적으로 동작하는 플러그인 구조를 만들어 분업화 하는 것이 바람직함

플러그인 구조

  • 플러그인은 다수의 모듈과 게임 컨텐츠를 포함하는 포장 단위
  • 에디터 설정을 통해 유연하게 플러그인을 추가하거나 삭제할 수 있음
  • 플러그인 구조
    • 플러그인 명세서(uplugin 파일)
    • 플러그인 리소스(Resource 폴더, 에디터 메뉴용 아이콘)
    • 컨텐츠
    • 모듈 폴더
  • 이러한 플러그인은 마켓 플레이스 판매로도 이어질 수 있도록 여러 설정을 추가할 수 있음 

게임 빌드

  • 게임 타겟 설정을 추가하면 게임 빌드 옵션이 추가됨.
  • 게임 타겟으로 빌드된 모듈은 정적 라이브러리로 실행 파일에 포함됨
  • 게임이 실행되기 위해서는 실행 파일과 콘텐츠 에셋이 함께 있어야 함
  • 빌드: 실행 파일을 생성하기 위한 컴파일
  • 쿠킹: 지정한 플랫폼에 맞춰 컨텐츠 에셋을 변환하는 작업
  • 패키징: 이들을 모두 모아서 하나의 프로그램으로 만드는 작업
  • 에디터의 Platforms -> binary Configuration 항목에서 shipping 옵션 선택 후 패키징하면 쿠킹까지 같이 해준다.

댓글()

언리얼 오브젝트 관리 - 패키지

Unreal 이론|2024. 10. 1. 17:50

[이득우의 언리얼 프로그래밍 수업의 정리]

 

언리얼 오브젝트 패키지

  • 단일 언리얼 오브젝트가 가진 정보는 저장o
  • 오브젝트들이 조합되어 있다면
    • 저장된 언리얼 오브젝트 데이터를 효과적으로 찾고 관리하는 방법 필요
    • 복잡한 계층 구조 가진 언리얼 오브젝트 효과적으로 저장과 불러들일 방법 통일 필요
  • 이를 위해 언리얼은 패키지(UPackage) 단위로 언리얼 오브젝트 관리
  • 패키지의 중의적 개념
    • 언리얼 엔진은 다양한 곳에서 단어 "패키지" 사용
    • 이번에는 오브젝트를 감싼 포장 오브젝트 의미
    • 개발된 최종 컨텐츠를 정리해 프로그램으로 만드는 작업 의미하기도 함 (게임 패키징)
    • DLC와 같이 향후 확장 컨텐츠에 사용되는 별도의 데이터 묶음 의미하기도 함 (pkg 파일)
    • 구분하기 힘들면 언리얼 오브젝트 패키지로 부르는것도?

패키지와 에셋

  • 언리얼 오브젝트는 다수의 언리얼 오브젝트를 포장하는데 사용한 언리얼 오브젝트
    • 모든 언리얼 오브젝트는 패키지에 소속되어 있음 (Transient Package)
  • 언리얼 오브젝트 패키지의 서브 오브젝트들을 에셋이라고 하며 에디터에는 에셋이 노출됨
  • 구조상 패키지는 다수의 언리얼 오브젝트 소유 가능, 일반적으론 하나의 에셋만 가짐
  • 에셋은 다시 다수의 언리얼 오브젝트 소요할 수 있지만, 일반적으론 하나의 에셋만 가짐
  • 에셋은 다시 다수의 서브 오브젝트 가질 수 있으며, 모두 언리얼 오브젝트 패키지에 포함됨
    • 에디터에 노출되진 않음

언리얼 오브젝트 패키지. 에셋이 에디터에 보여지는 정보이다.

에셋 정보의 저장과 로딩 전략

  • 게임 제작 단계에서 에셋간 연결작업을 위해 직접 패키지를 불러 할당하는 작업은 부하 큼
    • 에셋 로딩 대신 패키지와 오브젝트를 지정한 문자열을 대체해 사용 -> 이것이 오브젝트 경로
    • 프로젝트 내에 오브젝트 경로값은 유일함을 보장
    • 때문에 오브젝트간 연결은 오브젝트 경로 값으로 기록 가능
    • 오브젝트 경로 통해 다양한 방법으로 에셋 로딩 가능
  • 에셋 로딩 전략
    • 프로젝트에서 에셋 반드시 필요 : 생성자 코드에서 미리 로딩
    • 런타임에서 필요한 때 바로 로딩 : 런타임 로직에서 정적 로딩
    • 런타임에서 비동기 로딩하는 경우 : 런타임 로직에서 언리얼이 제공하는 관리자 사용해 비동기 로딩

오브젝트 경로

  • 패키지 이름과 에셋 이름을 한데 묶은 문자열
  • 에셋 클래스 정보는 생략 가능
  • 패키지 내 데이터를 모두 로드하지 않고 오브젝트 경로를 사용해 필요한 에셋만 로드 가능
  • {에셋 클래스 정보}'{패키지 이름}.{에셋 이름}' or {패키지 이름}.{에셋 이름}

에셋 스트리밍 관리자 (Streamable Manager)

  • 에셋의 비동기 로딩 지원하는 관리자 객체
  • 콘텐츠 제작과 무관한 싱글턴 클래스에 FStreamableManager 선언해두면 좋음
    • GameInstance는 좋은 선택지
  • FStreamableManager를 활용해 에셋의 동기/비동기 로딩 관리
  • 다수의 오브젝트 경로 입력해 다수의 에셋 로딩하는것도 가능
  • 생성자 코드에 생성한 에셋이 존재하지 않으면 에러가 나기 때문에 에셋이 빠지지 않도록 잘 세팅해야 함

'Unreal 이론' 카테고리의 다른 글

언리얼 엔진 게임 제작 기초  (0) 2024.10.14
언리얼 빌드 시스템  (1) 2024.10.03
언리얼 오브젝트 관리 - 직렬화  (0) 2024.09.12
언리얼 엔진의 메모리 관리  (1) 2024.09.05
언리얼 네트워킹 개요  (3) 2024.09.02

댓글()

언리얼 오브젝트 관리 - 직렬화

Unreal 이론|2024. 9. 12. 17:24

[이득우의 언리얼 프로그래밍 수업의 정리]

 

직렬화(Serializaion)란?

  • 오브젝트나 연결된 오브젝트의 묶음(오브젝트 그래프)을 바이트 스트림으로 변환하는 과정.
    • 복잡한 데이터를 일렬로 세우기 때문에 직렬화
  • 거꾸로 복구시키는 과정도 포함
    • 시리얼라이제이션: 오브젝트 그래프에서 바이트 스트림으로
    • 디시리얼라이제이션: 바이트스트림에서 오브젝트 그래프로
  • 장점
    • 현재 프로그램의 상태를 저장하고 필요한 때 복원(게임의 저장)
    • 현재 객체의 정보를 클립보드에 복사해서 다른 프로그램에 전송
    • 네트워크를 통해 현재 프로그램의 상태를 다른 컴퓨터에 복원(멀티플레이어 게임)
    • 데이터 압축, 암호화 통해 데이터를 효율적이고 안전하게 보관

직렬화 구현시 고려할 점

  • 직접 구현할경우 다양한 상황 고려 필요
    • 데이터 레이아웃: 오브젝트가 소유한 다양한 데이터를 변환할것인가?
    • 이식성: 서로 다른 시스템에 전송해도 이식될 수 있는가? (예시: 운영체제마다 다른 빅엔디안, 리틀엔디안 차이)
    • 버전 관리: 새로운 기능이 추가될 때 이를 어떻게 확장하고 처리할것인가?
    • 성능: 네트웍 비용을 줄이기 위해 어떤 데이터 형식 사용?
    • 보안: 데이터 어떻게 안전하게 보호?
    • 에러 처리: 전송과정에서 문제 발생시 이를 어떻게 인식하고 처리할것인가?
  • 이런 상황 모두 감안해 직렬화 모델 만드는것 쉽지않다.

언리얼 엔진의 직렬화 시스템

  • UE엔진은 이런 상황을 모두 고려한 직렬화 시스템 자체 제공
  • FArchive 클래스와 연산자 제공
    • 아카이브 클래스 - FArchive
    • shift(<<) operator
  • 다양한 아카이브 클래스 제공
    • 메모리 아카이브(FMemoryReader, FMemoryWriter)
    • 파일 아카이브(FArchiveFileReaderGeneric, FArchiveFileWriterGeneric)
    • 기타 언리얼 오브젝트와 관련된 아카이브 클래스(FArchiveUObject)
  • Json 직렬화 기능: 별도 라이브러리 통해 제공
  • 장점
    • 텍스트지만 데이터 크기 가벼움
    • 읽기 편해서 데이터 보고 이해 가능
    • 사실상 웹 통신의 표준급으로 널리 사용됨
  • 단점
    • 지원하는 타입 몇개안됨
    • 텍스트 형식으로만 사용 가능
  • 언리얼 엔진의 Json -> JsonUtilities 라이브러리 활용

언리얼 스마트 포인터 라이브러리 개요

  • 일반 C++ 오브젝트의 포인터 문제 해결해주는 언리얼 엔진의 라이브러리
  • TUniquePtr(유니크 포인터)
    • 지정한 곳에서만 메모리 관리하는 포인터
    • 특정 오브젝트에게 명확하게 포인터 해지 권한 주고싶은 경우
    • delete 구문 없이 함수 실행 후 자동으로 소멸시키고 싶을 때
  • TSharedPtr(공유 포인터)
    • 더 이상 사용되지 않으면 자동으로 메모리 해지하는 포인터
    • 여러 로직에서 할당된 오브젝트가 공유해서 사용하는 경우
    • 다른 함수로부터 할당된 오브젝트를 Out으로 받는 경우
    • Null 일 수 있음
  • TSharedRef(공유 레퍼런스)
    • 공유포인터와 동일하지만 유효한 객체 항상 보장받는 레퍼런스
    • 여러 로직에서 할당된 오브젝트가 공유해서 사용하는 경우
    • Not Null 보장받으며 오브젝트 편리하게 사용하고 싶은 경우

댓글()