본문 바로가기
Unreal

[UE4 입문] 언리얼 엔진 기초

by imagineer_jinny 2022. 6. 20.

본 내용은 [Rookiss - 언리얼 엔진4 입문(C++ 기반)] 강의를 토대로 작성하였습니다.

 

  • 유니티 vs 언리얼
    • 유니티와 다르게 언리얼은 클래스 생성시 빈 깡통에서 시작하는게 아니라 태생을 정함
    • 상속 구조를 이용해서 내가 Actor가 될거면 Actor를 상속 받은 후 이런 저런 기능 붙이는 것

 

  • Actor와 Pawn
  • Actor : 월드에 배치 또는 스폰할 수 있는 오브젝트
  • Pawn : 빙의하면 컨트롤러에서 입력 받을 수 있는 엑터, Actor에서 상속받아서 기능 추가 한 것
  • 차이 : Pawn은 Actor에게 상속 받아 키보드 입력 받을 수 있다.

 

유니티에서의 Start(), Update() 함수와 비슷한 기능

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

 

  • UPROPERTY()
    • 언리얼에서 만든 리플렉션 기능
    • UPROPERTY(VisibleAnywhere)
    • UPROPERTY(EditAnywhere, Category=BattleStart)

 

  • 로그와 디버깅
  • 로그
// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
	Super::BeginPlay();

	//카테고리, 로깅 수준, 형식, 인자
	UE_LOG(LogTemp, Warning, TEXT("BeginPlay %d"), 3);
	
}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	UE_LOG(LogTemp, Error, TEXT("Tick %f"), DeltaTime);

}

  • 디버깅

 

  • 물체 회전시키기
//MyActor.cpp

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	
	AddActorLocalRotation(FRotator(0.f,RotateSpeed * DeltaTime, 0.f));

}
//MyActor.h

private:

	UPROPERTY(VisibleAnywhere)
	UStaticMeshComponent* Mesh;

	UPROPERTY(EditAnywhere, Category = BattleStart)
	float RotateSpeed = 30.f;

 

  • 게임 플레이 프레임워크

 

  • Pawn 생성

//MyGameModeBase.h

class TESTUNREALENGINE_API AMyGameModeBase : public AGameModeBase
{
	GENERATED_BODY()

	AMyGameModeBase();
	
};
//MyGameModeBase.cpp

#include "MyGameModeBase.h"
#include "MyPawn.h"

AMyGameModeBase::AMyGameModeBase()
{
	DefaultPawnClass = AMyPawn::StaticClass();
	
}

 

Pawn이 Actor와 다른 점? 입력을 받을 수 있다! 빙의를 할 수 있다!

 

  • 캐릭터 생성
/** The main skeletal mesh associated with this Character (optional sub-object). */
	UPROPERTY(Category=Character, VisibleAnywhere, BlueprintReadOnly, meta=(AllowPrivateAccess = "true"))
	USkeletalMeshComponent* Mesh; //뼈대를 이용해서 움직일 수 있는 메쉬

	/** Movement component used for movement logic in various movement modes (walking, falling, etc), containing relevant settings and functions to control movement. */
	UPROPERTY(Category=Character, VisibleAnywhere, BlueprintReadOnly, meta=(AllowPrivateAccess = "true"))
	UCharacterMovementComponent* CharacterMovement; //복잡한 이동 가능 (ex. 쭈그리기 등등)

	/** The CapsuleComponent being used for movement collision (by CharacterMovement). Always treated as being vertically aligned in simple collision check functions. */
	UPROPERTY(Category=Character, VisibleAnywhere, BlueprintReadOnly, meta=(AllowPrivateAccess = "true"))
	UCapsuleComponent* CapsuleComponent; // 충돌 범위 나타내는 캡슐

 

카메라 위치 조절 + 캐릭터에 셀카봉 달기(Top-Down)

AMyCharacter::AMyCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SPRINGARM"));
	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("CAMERA"));
	
	SpringArm->SetupAttachment(GetCapsuleComponent());
	Camera->SetupAttachment(SpringArm);

	SpringArm->TargetArmLength = 500.f;
	SpringArm->SetRelativeRotation(FRotator(-35.f,0.f,0.f));

	GetMesh()->SetRelativeLocationAndRotation(
		FVector(0.f, 0.f, -88.f), FRotator(0.f, -90.f, 0.f));
	
	static ConstructorHelpers::FObjectFinder<USkeletalMesh> SM(TEXT("SkeletalMesh'/Game/ParagonYin/Characters/Heroes/Yin/Meshes/Yin.Yin'"));

	
	if (SM.Succeeded())
	{
		GetMesh()->SetSkeletalMesh(SM.Object);
	}

}

 

완성된 하이라키

 

 

  • 마우스 돌릴 때 회전 기능 넣기

세팅 -> 프로젝트 세팅 -> 입력 -> 축 매핑 추가

//MyCharacter.h

void UpDown(float Value);
void LeftRight(float Value);
void Yaw(float Value);


//MyCharacter.cpp

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

	PlayerInputComponent->BindAxis(TEXT("UpDown"), this, &AMyCharacter::UpDown);
	PlayerInputComponent->BindAxis(TEXT("LeftRight"), this, &AMyCharacter::LeftRight);
	PlayerInputComponent->BindAxis(TEXT("Yaw"), this, &AMyCharacter::Yaw);
}

void AMyCharacter::Yaw(float Value)
{
	AddControllerYawInput(Value);
}

 

  • 블루프린트 클래스

왜 써?

성능이 중요하면 C++, 하지만 성능적으로 안좋고(코드에 비해 10배정도 느림) 간단한거 만들기엔 좋음

작업하기 직관적이다

GameMode 같은 경우도 중간 중간 자주 바뀔 수 있으니 블루 프린트로 만들어서 저장해주면 편리할 수 있음

 

 

블루프린트에서는 경로복사 후 뒤에 _C를 꼭 붙일 것!

 

 

AMyGameModeBase::AMyGameModeBase()
{
	//코드로 할 때
	//DefaultPawnClass = AMyCharacter::StaticClass();
	
	//블루 프린트로 바꾸기
	static ConstructorHelpers::FClassFinder<ACharacter>BP_Char(TEXT("Blueprint'/Game/Blueprints/BP_MyCharacter.BP_MyCharacter_C'"));

	if (BP_Char.Succeeded())
	{
		DefaultPawnClass = BP_Char.Class;
	}
}

 

 

  • 블루 프린트 클래스를 만들 때는 C++ 클래스를 상속 받아 만들 수 있음
  • 하지만 거꾸로는 되지 않음

댓글