언리얼엔진 학습 및 과제

게임 루프 및 UI 재설계 과제 (3)

park94128 2025. 10. 1. 23:29

5. 아이템 액터 만들기

A. C++로 아이템 액터 만들기

이제 슬슬 코딩을 할 때가 왔다. 맵에 배치할 아이템은 C++클래스를 추가하여 만든다. 콘텐츠 브라우저에서 C++ 클래스 안에 있는 폴더에서 '새 C++ 클래스'를 누르고 액터를 추가한다. 이름은 'ItemActor'라고 명명했다.

 

private:
    //아이템 판정 범위
	UPROPERTY(EditDefaultOnly, meta = (AllowPrivateAccess = true))
	USphereComponent* sphereCollider;

	//아이템의 스태틱 메시
	UPROPERTY(EditDefaultOnly, meta = (AllowPrivateAccess = true))
	UStaticMeshComponent* itemMesh;

헤더에서 아이템 판정 범위를 위한 SphereComponent와 아이템을 시작적으로 보여줄 StaticMeshComponent를 선언했다. 이들은 나중에 블루프린트로 만들때 내용을 수정해야 하니 UPROPTY를 선언했으며 EditDefaultOnly를 적었다. 나같은 경우 이 선언을 private에 했으니 AllowPrivateAccess도 넣었다.

 

EditDefaultOnly대신 EditAnywhere를 사용해도 동일하게 작동한다. 둘의 차이는 맵에 배치된 객체에 대한 수정 가능 여부에 있다. 블루프린트에서 편집할 때는 아무런 차이가 없다.

 

AItemActor::AItemActor()
{
	PrimaryActorTick.bCanEverTick = true;

	//아이템 범위를 루트로
	sphereCollider = CreateDefaultSubobject<USphereComponent>(FName("SphereCollider"));
	RootComponent = sphereCollider;

	//스태틱 메시
	itemMesh = CreateDefaultSubobject<UStaticMeshComponent>(FName("ItemMesh"));
	itemMesh->SetupAttachment(sphereCollider);
}

 

생성자를 통해 두 컴포넌트를 만들어준다. 여기서 SphereComponent를 루트로 지정한다.

여기까지 작성한 것을 컴파일해보자.(에디터 화면의 오른쪽 아래에 있다.) 다만 '라이브 코딩 활성화'는 기본적으로 켜진 상태인데 끄고 하는 것이 좋다.

 

컴파일을 완료했으면 일단 맵에다 집어넣어본다. 구체 형상이 보이는 걸 보니 잘 만들어졌다. 스태틱 메시는 지정한게 없으니 안보이는게 정상이다.

디테일 화면에서도 컴포넌트가 잘 들어간 상태다.

 

확인을 완료했으면 맵에 배치한 액터는 도로 지운다.

 

B. 코드 기반 액터를 상속받는 블루프린트

콘텐츠 브라우저에서 블루프린트용 폴더인 'Blueprint'를 만든다. 그다음 이 폴더에 들어간 상태에서 오른쪽 클릭하여 블루프린트 클래스를 만들자. 상속받는 액터는 코드로 생성한 ItemActor로 지정한다.

 

블루프린트 액터는 코드로 만든 액터와 구분을 쉽게 하기 위해 이름을 명명할때는 앞에 BP를 붙인다.

이 액터를 열어서 스태틱 메시 컴포넌트에 적절한 메시를 부여한다. 내가 쓰는 에셋에 구급약 메시가 있길래 사용해봤다.

아이템은 캐릭터와 겹쳐지면서 이벤트를 발생해야 한다. 그래서 캐릭터에 해당되는 Pawn에 대하여 오버랩으로 체크된 콜리전 프리셋으로 지정한다. 아니면 Custom으로 지정해서 Pawn을 무시하게 직접 설정한다. 나는 'OverlapOnlyPawn'프리셋을 골랐다.

 

블루 프린트를 컴파일 하고 저장한다.

 

아이템을 맵에다 배치해보니 2가지 문제를 발견했다.

- 너무 작아서 잘 안보이는 문제가 생겼다.

- 스태틱 메시가 캐릭터를 막아버린다.

 

스태틱 메시의 크게 만들자. 크기에 맞게 SphereCompoenet의 크기도 조절한다.

 

스태틱 메시의 콜리전 프리셋을 변경한다. 캐릭터인 Pawn을 무시해야 한다.

문제 해결 완료

C. 캐릭터와 겹칠때의 이벤트 구현

//ItemActor.h

protected:
	virtual void BeginPlay() override;
	virtual void PostInitializeComponents() override;
//ItemActor.cpp

void AItemActor::PostInitializeComponents()
{
	Super::PostInitializeComponents();
}

액터 클래스는 PostInitializeComponents함수를 상속받아 구현할 수 있다. 원본 코드가 BeginPlay와 동일한 protected로 선언됐으니 BeginPlay 밑에 만들어 놓자

 

이 함수는 게임상 액터가 작동하기 시작할 때 실행하는 BeginPlay보다 먼저 실행되는 함수로, 이름대로 컴포넌트 초기화 시점에 실행된다.

private:
	//캐릭터와 겹칠 때 실행
	UFUNCTION()
	void OnCharacterOverlap(UPrimitiveComponent* overlappedComp, AActor* otherActor, UPrimitiveComponent* otherComp, int otherBodyIndex, bool fromSweep, const FHitResult& sweepResult);

그리고 아이템과 캐릭터가 겹칠 때 실행할 함수를 만들자. 매개변수가 꽤 많다.

 

void AItemActor::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	sphereCollider->OnComponentBeginOverlap.AddDynamic(this, &AItemActor::OnCharacterOverlap);
}

SphereComponent에는 OnComponentBeginOverlap 이벤트가 있다. 영어를 잛 보면 알겠지만 컴포넌트가 무언가와 겹칠때 이 이벤트가 발생한다. 캐릭터와 겹칠 때 실행할 함수를 이 이벤트에 등록한다. 함수의 매개변수가 많은 이유가 이 이벤트에 등록하기 위해서였다. 매개변수를 하나라도 빼먹거나 순서가 틀리면 등록을 못한다.

 

이벤트 등록은 PostInitializeComponents에서 하면 된다.

 

void AItemActor::OnCharacterOverlap(UPrimitiveComponent* overlappedComp, AActor* otherActor, UPrimitiveComponent* otherComp, int otherBodyIndex, bool fromSweep, const FHitResult& sweepResult)
{
	UE_LOG(LogTemp, Warning, TEXT("Get Item"));
	Destroy();
}

지금은 간단한 구현이 목표니까 호출될 함수의 내용은 일단 이렇게 적었다. 캐릭터가 아이템에 닿으면 로그를 출력하면서 사라질것이다.

 

컴파일 하고 실행해보니 예상한대로 작동했다.