[ Unreal Engine 5 / #12 Shop & Item & Inventory2 ]

SeungWoo·2024년 9월 24일
0

[ Ureal Engine 5 / 수업 ]

목록 보기
13/31
post-thumbnail

Widget

  • 인벤토리 창을 만들기 위해 BlueprintWidget를 하나 만든다

  • 이름은 WBP_ItemShop으로 하겠습니다

  • 간단한 디자인 영역이라 더 이쁘게 만들어도 될꺼같은데 전 간단하게 만들겠습니다

  • NPC를 누를시 해당 위젯을 띄우기 위해 NPC 클래스에 위젯 클래스를 선언하고 해당 위젯을 띄우기 위해 Interaction 함수에 반응시 해당 위젯을 나타내는 로직을 작성

NPC.h

protected:
	UPROPERTY()
	class UUserWidget* itemShopWidget;

NPC.cpp


void ANPC::Interaction()
{
	//UE_LOG(LogTemp, Log, TEXT("Interacted with object"));
	// 상호 작용 로직

	APlayerController* myPlayerController = UGameplayStatics::GetPlayerController(this, 0);

	myPlayerController->SetViewTargetWithBlend(this, 1.0f);
	myPlayerController->SetInputMode(FInputModeUIOnly());
	myPlayerController->SetShowMouseCursor(true);

	HideInteractionWidget();

	if (ItemShopWidgetClass)
	{
		itemShopWidget = CreateWidget<UUserWidget>(GetWorld(), ItemShopWidgetClass);

		if (itemShopWidget)
			itemShopWidget->AddToViewport();
    }
 }

  • 해당 위젯이 뜨면 다음엔 Exit 버튼을 누를시 다시 컨트롤러를 Player로 바꾸겠습니다

  • 위젯의 기능이나 또는 그런 부분은 블루 프린트로 간단하게 표현할 예정이다

  • Button click 이벤트 처리를 블루프린트

Inventory

해당 본격 상점 인벤토리를 만들기 위해 위젯을 하나 더 만든다

  • 해당 canvas 없이 만들어 놓고 윗 부분의 TEXT에는 아이템 이름이 아랫 부분의 TEXT에는 가격을 표시할 예정이다
  • 가운데는 아이템 ICON를 넣을 예정이다

  • 이름을 ItemGrid라고 짓고, Is Variable 체크 표시 한뒤를 하면서 블루프린트에 변수로 사용할 수 있게 할것이다

  • 해당 Structure를 하나 만들고, C++ 구조체를 이용한 해당 아이템을 나열 할 것이다

  • Data Table도 하나 만든다

  • Test용으로 쓰기 위해 마켓 플레이스 가서 해당 아이콘 에셋을 다운 받는다

가상 예제로 DataTable 만들기

  • 해당 Mesh는 그냥 Icon 대로 쓰면 되므로 저부분을 쓰지말고, 본인이 다운 받은 ICON 위치를 넣으면 된다

  • 해당 블루프린트 변수를 선언하고, 인스턴스에서 해당 네임을 관리하기 위해 Instance Editable 부분을 체크 한다
  • 생성후, 해당 Name을 Data에 저장해둔 Name을 가져와 쓰기 위해 Expose on Spawn 도 체크 한다

  • C++ 클래스로 해당 해당 NPC마다 각각의 다른 Item를 팔게끔 만들어 보자

NPC.cpp

void ANPC::Interaction()
{
	//UE_LOG(LogTemp, Log, TEXT("Interacted with object"));
	// 상호 작용 로직

	APlayerController* myPlayerController = UGameplayStatics::GetPlayerController(this, 0);

	myPlayerController->SetViewTargetWithBlend(this, 1.0f);
	myPlayerController->SetInputMode(FInputModeUIOnly());
	myPlayerController->SetShowMouseCursor(true);

	HideInteractionWidget();

	if (ItemShopWidgetClass)
	{
		itemShopWidget = CreateWidget<UUserWidget>(GetWorld(), ItemShopWidgetClass);

		if (itemShopWidget)
			itemShopWidget->AddToViewport();

		FName Property(TEXT("OwnerNPC"));
		FProperty* _NPCPropert = itemShopWidget->GetClass()->FindPropertyByName(TEXT("OwnerNPC"));

		if (_NPCPropert)
		{
			FObjectProperty* ObjectProperty = CastField<FObjectProperty>(_NPCPropert);

			if (ObjectProperty && ObjectProperty->PropertyClass == ANPC::StaticClass())
			{
				ObjectProperty->SetObjectPropertyValue_InContainer(itemShopWidget, this);
			}
		}

	}
}
FName Property(TEXT("OwnerNPC"));
FProperty* _NPCPropert = itemShopWidget->GetClass()->FindPropertyByName(TEXT("OwnerNPC"));
  • 블루프린트 변수 'OwnerNPC'에 접근
  • 'Expose on Spawn'가 활성화된 NPC 변수를 설정
  • 블루프린트 위젯에 'OwnerNPC'라는 이름으로 설정된 변수 ( Expose on Spanw 옵션이 활성화 된 변수 )를 찾습니다.
if (_NPCPropert)
  • _NPCProperty가 유효한지 확인
  • 위의 FindPropertyByName 함수가 정상적으로 'OwnerNPC' 변수를 확인합니다
  • 만약 'OwnerNPC'라는 변수를 블루프린트 위젯에서 찾지 못했다면 _NPCProperty는 nullptr이 됩니다.
FObjectProperty* ObjectProperty = CastField<FObjectProperty>(_NPCPropert);
  • 찾은 _NPCPropert변수를 FObjectProperty로 캐스팅
  • _NPCPropert가 객체 타입의 변수의 경우에만 FObjectProperty로 캐스팅 할 수 있습니다
  • 여기서 'OwnerNPC'가 ANPC 타입의 객체 변수이므로 FObjectProperty로 캐스팅 시도 합니다
if (ObjectProperty && ObjectProperty->PropertyClass == ANPC::StaticClass())
  • FObjectProperty가 유효한지 확인하고, 이 변수가 ANPC 클래스와 일치한지 확인
  • FObjectProperty가 유요하고, 그 변수가 정확히 ANPC 클래스의 객체인 경우에만 아래 코드를 실행합니다
ObjectProperty->SetObjectPropertyValue_InContainer(itemShopWidget, this);
  • 찾은 FObjectProperty 변수에 현재 NPC 객체( this )를 할당
  • SetObjectPropertyValue_InContainer 함수는 주어진 객체 ( itemShopWidget ) 의 특정 객체 변수 ( ObjectProperty )에 값을 설정해줍니다
  • 여기서는 itemShopWidget 위젯의 OwnerNPC 변수에 현재 NPC 객체 ( this )를 설정하는 역할을 합니다

생성과 동시에 할당된 변수를 사용해서, ‘OwnerNPC’ 의 Null Error 가 발생

해결해보자

  • 보여지는 부분이 먼저 작동하고 그 후에 NPC가 할당되어 값을 제대로 전달 받지 못해 이러나는 현상이다

NPC.cpp

void ANPC::Interaction()
{
	//UE_LOG(LogTemp, Log, TEXT("Interacted with object"));
	// 상호 작용 로직

	APlayerController* myPlayerController = UGameplayStatics::GetPlayerController(this, 0);

	myPlayerController->SetViewTargetWithBlend(this, 1.0f);
	myPlayerController->SetInputMode(FInputModeUIOnly());
	myPlayerController->SetShowMouseCursor(true);

	HideInteractionWidget();

	if (ItemShopWidgetClass)
	{
		itemShopWidget = CreateWidget<UUserWidget>(GetWorld(), ItemShopWidgetClass);


		// 블루프린트 변수 'OwnerNPC'에 접근
		FName Property(TEXT("OwnerNPC"));
		FProperty* _NPCPropert = itemShopWidget->GetClass()->FindPropertyByName(TEXT("OwnerNPC"));

		if (_NPCPropert)
		{

			FObjectProperty* ObjectProperty = CastField<FObjectProperty>(_NPCPropert);


			if (ObjectProperty && ObjectProperty->PropertyClass == ANPC::StaticClass())
			{
				ObjectProperty->SetObjectPropertyValue_InContainer(itemShopWidget, this);
			}
		}
		
		if (itemShopWidget)
			itemShopWidget->AddToViewport();
        // 위치를 바꾸주면 해결된다 
	}
}
profile
This is my study archive

0개의 댓글