언리얼 5

230925 인벤토리 설명 UI tooltip / 마우스 / 빌보드 컴포넌트

슬뷔 2023. 9. 25. 11:31

인벤토리 설명 UI ( Tooltip )

=> 아이템에 마우스 올렸을 때 아이템의 설명이 나온다

 

UUserWidget 상속받은 Tooltip_Base 생성

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Tooltip_Base.generated.h"

UCLASS()
class UNREAL_3TH_API UTooltip_Base : public UUserWidget
{
	GENERATED_BODY()
	
private:
	class UTextBlock* m_Description;

public:
	UTextBlock* GetTextBlock() { return m_Description; }

public:
	virtual void NativeConstruct() override;
	virtual void NativeTick(const FGeometry& _geo, float _DT) override;
};
#include "Tooltip_Base.h"

#include "Components/TextBlock.h"

void UTooltip_Base::NativeConstruct()
{
	Super::NativeConstruct();

	m_Description = Cast<UTextBlock>(GetWidgetFromName(TEXT("Description")));
}

void UTooltip_Base::NativeTick(const FGeometry& _geo, float _DT)
{
	Super::NativeTick(_geo, _DT);
}

 

유저인터페이스 -> 위젯블루프린트 -> Tooltip 블루 프린트 제작

Tooltip의 경로를 복제해서 Inventory_Base 에 Tooltip Blueprint 클래스 정보 가져오기

void UInventory_Base::NativeConstruct()
{
	Super::NativeConstruct();

	m_ListView = Cast<UListView>(GetWidgetFromName(L"ListView"));

	if (!IsValid(m_ListView))
	{
		LOG(LogTemp, Error, TEXT("ListView 못 찾음"));
	}

	else
	{
		// Tooltip_Base 를 상속받은 Tooltip Blueprint 클래스 정보 가져오기
		UBlueprintGeneratedClass* TooltipClass = LoadObject<UBlueprintGeneratedClass>(nullptr, TEXT("/Script/UMGEditor.WidgetBlueprint'/Game/BlueprintClass/UMG/Inventory/Tooltip.Tooltip'_C"));
		if (IsValid(TooltipClass))
		{
			// Blueprint 클래스 정보로 실제 객체하나 만들어서 ListView 의 Tooltip 용으로 전달하기 
			m_ListView->SetToolTip(CreateWidget(GetWorld(), TooltipClass));
		}
	}
}

리스트뷰에서 데이터를 저장하고 화면에 노출할 용으로 itembase 를 선택

class UNREAL_3TH_API UInventory_Base : public UUserWidget
{
	GENERATED_BODY()

public:
	void OnHovered(UObject* _Data, bool _hovered);
};
void UInventory_Base::OnHovered(UObject* _Data, bool _hovered)
{
	if (_hovered)
	{
		// 마우스 호버한 아이템 위젯과 연결되어있는 데이터 가져옴
		UInvenItemData* pData = Cast<UInvenItemData>(_Data);

		// ListView 에 넣어둔 툴팁용 위젯 객체 가져옴
		UTooltip_Base* pTooltip = Cast<UTooltip_Base>(m_ListView->ToolTipWidget);

		// 툴팁 위젯의 TextBlock 에 Item Description 정보 문자열 전달
		pTooltip->GetTextBlock()->SetText(FText::FromString(pData->GetItemDescription()));

		// 툴팁 위젯 시각화
		m_ListView->ToolTipWidget->SetVisibility(ESlateVisibility::Visible);
	}
	else
	{
		m_ListView->ToolTipWidget->SetVisibility(ESlateVisibility::Hidden);
	}
}

InvenMgr 에 디스크립션 세팅하기

void UInvenMgr::ResetWidget()
{
	// InvenMgr 가 보유하고 있는 아이템목록을 전부 UI 로 보내기
	for (int32 i = 0; i < (int32)EITEM_TYPE::END; ++i)
	{
		for (auto Iterator = m_BackPack[i].CreateConstIterator(); Iterator; ++Iterator)
		{
			pData->SetItemDescription(Iterator.Value().ItemInfo->Description);
		}
	}
}

마우스

1. 하드웨어 커서 -> GPU 가 제공하는 기본 커서에 텍스쳐를 띄워준다

상대경로 : Texture/UI/MouseDefault

이렇게 잡아주어야하고, 뒤에 확장자명은 붙일 필요 없다

 

2. 소프트웨어 커서 -> 언리얼기능을 사용할 수 있다 ( 위젯클래스로 디자인된 UI 를 마우스로 지정할 수 있다

=> UI 기능 다 사용 가능

위젯을 생성해서 커서에 맞는 위젯을 넣어준다

특정 대상 위에 올라갔을 때 이미지 교체

1. 마우스 방향으로 ray 를 쏴서 거기에 충돌된 애가 누구인지 따라서 상태 변경

=> 플레이어 컨트롤러가 매 틱마다 ray를 쏴야한다

 

단점 : 매 틱마다 레이를 쏴서 충돌 검사를 해야함 ( 쓸데없는 충돌연산이 많음 )

 

APlayerController 를 상속받은 MyPlayerController 생성

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

UCLASS()
class UNREAL_3TH_API AMyPlayerController : public APlayerController
{
	GENERATED_BODY()
	
public:
	virtual void Tick(float _DT) override;

public:
	AMyPlayerController();
};
#include "MyPlayerController.h"
#include "../Monster/Monster_Base.h"

AMyPlayerController::AMyPlayerController()
{
}

void AMyPlayerController::Tick(float _DT)
{
	Super::Tick(_DT);

	// 플레이어 컨트롤러에서 매 틱마다 마우스 위치로 RayCastiong 시도
	FHitResult result = {};
	// 트레이스 채널 5 => PlayerAttack 이라서 몬스터가 걸리게 된다
	bool bHit = GetHitResultUnderCursor(ECC_GameTraceChannel5, false, result);

	// 마우스 방향 Ray Check 에 걸린 대상이 있다면
	if (bHit)
	{
		// 걸린 대상이 몬스터타입이면
		if (Cast<AMonster_Base>(result.GetActor()))
		{
			// 현재 마우스 상태를 GrabHand 로 변경한다
			CurrentMouseCursor = EMouseCursor::GrabHand;
		}
		else
		{
			CurrentMouseCursor = EMouseCursor::Default;
		}
	}

	// 충돌 중인 오브젝트가 없다면 항상 Default 로 둔다
	else
		CurrentMouseCursor = EMouseCursor::Default;
}

 

* 프로젝트 세팅 -> 유저인터페이스 -> 마우스설정 안해도 아래처럼 하면 컨트롤러 별로 마우스 셋팅을 다르게 할 수 있다.

AMyPlayerController::BeginPlay()
{
	ConstructorHelpers::FClassFinder<UUserWidget> MouseDefault(TEXT("/Script/UMGEditor.WidgetBlueprint'/Game/BlueprintClass/UMG/Mouse/Mouse.Mouse_C'"));
	ConstructorHelpers::FClassFinder<UUserWidget> MouseGrabHand(TEXT("/Script/UMGEditor.WidgetBlueprint'/Game/BlueprintClass/UMG/Mouse/GrabHand.GrabHand_C'"));
	
	SetMouseCursorWidget(EMouseCursor::Default, CreateWidget(GetWorld(), MouseDefault.Class));
	SetMouseCursorWidget(EMouseCursor::GrabHand, CreateWidget(GetWorld(), MouseGrabHand.Class));
}

 

2. 마우스 체크 주체가 object 가 되어서, object 가 마우스가 자기 위에 올라와있는지 체크해서 마우스 상태 변경

=> Mouse Hovered 가 켜진 것만 검사 진행

대상이 위젯이냐 액터냐에 따라 또 달라진다

(1) 위젯

인벤토리-> 계층구조 전부 -> 디테일 -> 비헤이비어 -> 커서 

(2) 액터

AMyPlayerController::AMyPlayerController()
{
	bEnableMouseOverEvents = true;
}

 

 


빌보드 컴포넌트

=> 화면을 향해서 쳐다본다

 

머테리얼 빌보드 컴포넌트 ( 빌보드 컴포넌트 보다 약간 더 확장성이 있다 ) 

=> 어떻게 랜더링될건지에 대한 종합적인 파이프라인을 작성해놓은 재질을 골를 수 있다


Alt + 2 => 와이어모드 / Alt + 3 => 라이팅 적용되지 않은 순수한 색 / Alt + 4 => 원래 상태로 복구 (라이팅 적용)


요즘 상용엔진은 Deferred Render 를 사용하면서 MRT (multi render target) 을 사용한다.

랜더링 파이프라인 (언리얼)

오브젝트 좌표계 (로컬 스페이스) => 월드 => 카메라 릴레이티브 월드 스페이스 (뷰 스페이스) => z 축을 깊이로 하는 뷰스페이스로 변형

 

* 언리얼의 Camera Relative World Space 의 전방방향 => x 축