ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 블루아카이브 루트슈터 팬게임 프로젝트(6) - 아이템 툴팁 기능
    루트슈터 프로젝트 2024. 1. 2. 14:55

    안녕하세요. 어제 신정은 잘 쇠셨는지요? 저는 다음주에 이사를 가서 가기전에 버릴 짐들을 정리하고 야간알바를 하느라 개발 할 시간이 없었습니다. 아마도 이사가 끝나기 전까지는 여유가 많이 없을 것 같네요(핑계) 

     

     

     

    인벤토리에 있는 아이템에 마우스 커서를 올리면 그 아이템에 대한 스탯이 무엇인지 알려주는 기능이 있습니다. 이를 툴팁기능이라고 하는데요. RPG 게임에, 인벤토리가 있는 게임이라면 무조건 있어야 하는 UI입니다. 툴팁 기능 또한 언리얼에서 따로 제공해주는 기능이 있습니다. 언리얼은 정말 없는게 없네요 ㄷㄷ합니다 

    이번 기능은 껍데기방(https://husk321.tistory.com/432)님의 구현 코드를 참고하였습니다. 좋은 정보 감사합니다.

     

     

    UCLASS()
    class PROJECTBLUELANDS_API UWeaponTooltipWidget : public UUserWidget
    {
        GENERATED_BODY()
       
    public:
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<class UTextBlock> ItemName;
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<class UTextBlock> ItemLevel;
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<class UTextBlock> weaponDamage;
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<class UTextBlock> fireRate;
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<class UTextBlock> reloadTime;
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<class UTextBlock> maxMag;
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<class UTextBlock> criticalChance;
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<class UTextBlock> criticalDamage;
        UPROPERTY(BlueprintReadWrite, meta=(BindWidget))
        TObjectPtr<UMultiLineEditableText> weaponOption;


    };

     

     먼저 유저위젯 클래스를 상속받아서 새로운 C++ 클래스를 생성하고 툴팁에 어떤 정보를 보여줄것인지에 대해서 전부 BindWidget으로 들어갈 오브젝트들을 선언해줍니다. 아이템 이름 레벨, 무기데미지 무기 스탯....... 사실상 무기에 대한 모든 스탯 전부를 할당했습니다. 툴팁에서는 자세한 스탯을 볼 수 있게 해야하니까 어쩔 수 없습니다. 

     

     

    UISlot.h

    protected:
        virtual void NativeConstruct() override;
    private:
        UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
        TSubclassOf<UWeaponTooltipWidget> WeaponToolTipClass;
        UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
        TObjectPtr<UWeaponTooltipWidget> WeaponToolTipWidget;

        void SetWeaponToolTipWidget();

    그리고 NativeConstruct 함수를 오버라이드 해서 SetWeaponToolTipWidget(); 함수에서 툴팁 위젯을 셋업 할 수 있도록 하겠습니다. 그리고 WeaponToolTipClass 서브클래스를 기반으로 위젯을 하나 만들고 그것을 WeaponToolTipWidget 에 담기 위해 2개 위젯 관련 변수들을 선언했습니다.

     

     

     

    UISlot.cpp

    void UUISlot::NativeConstruct()
    {
        Super::NativeConstruct();
        SetWeaponToolTipWidget();
    }

     

    NativeConstruct에서 SetWeaponToolTipWidget을 호출하여 툴팁 위젯에 정보를 담아줍니다. 

     

    void UUISlot::SetWeaponToolTipWidget()
    {
        UE_LOG(LogTemp, Error, TEXT("정보를 기반으로 툴팁 생성중"));
        if(WeaponToolTipWidget) WeaponToolTipWidget = nullptr;
        if(player->itemInventory[slotNum].itemType != EItemType::EIT_GUN) return; //비어있는 인벤토리, 방어구라면 툴팁을 표시하지 않음

       
        // 툴팁 위젯 생성을 함
        if(WeaponToolTipClass == nullptr)   return;
        WeaponToolTipWidget = CreateWidget<UWeaponTooltipWidget>(this, WeaponToolTipClass);
        if(WeaponToolTipWidget == nullptr)  return;


        const auto dataItem = this->player->itemInventory[slotNum]; //인벤토리의 무기의 정보 받아오기

        WeaponToolTipWidget->ItemName->SetText(FText::FromName(dataItem.name));

        FString temp = FString::FromInt(int(dataItem.weaponStat.weaponDamage));
        WeaponToolTipWidget->weaponDamage->SetText(FText::FromString(temp));

        temp = FString::FromInt(int(dataItem.itemLevel));
        WeaponToolTipWidget->ItemLevel->SetText(FText::FromString(temp));

        temp = FString::SanitizeFloat(1.0 / dataItem.weaponStat.fireRate) + FString("/S");
        WeaponToolTipWidget->fireRate->SetText(FText::FromString(temp));

        temp = FString::SanitizeFloat(dataItem.weaponStat.reloadTime);
        WeaponToolTipWidget->reloadTime->SetText(FText::FromString(temp));

        temp = FString::FromInt(dataItem.weaponStat.maxMag);
        WeaponToolTipWidget->maxMag->SetText(FText::FromString(temp));

        temp = FString::SanitizeFloat(dataItem.weaponStat.critChance) + FString("%");
        WeaponToolTipWidget->criticalChance->SetText(FText::FromString(temp));

        temp = FString::SanitizeFloat(dataItem.weaponStat.critDamage) + FString("%");
        WeaponToolTipWidget->criticalDamage->SetText(FText::FromString(temp));

        FString optionText = "";
        for(int i = 1; i < 7; i++)
        {
            FString op;
            switch(i){
                case 1:
                op = FString("Weapon Damage +");
                break;
                case 2:
                op = FString("Fire Rate +");
                break;
                case 3:
                op = FString("Reload Speed +");
                break;
                case 4:
                op = FString("Magazine Size +");
                break;
                case 5:
                op = FString("Critical Chance +");
                break;
                case 6:
                op = FString("Critical Damage +");
                break;

            }

            if(dataItem.weaponStat.option[i] != 0.0)
            {
                optionText += op + FString::SanitizeFloat(dataItem.weaponStat.option[i]) + FString("%\n");
            }
        }
        WeaponToolTipWidget->weaponOption->SetText(FText::FromString(optionText));

        //this->SetToolTip(WeaponToolTipWidget);
        icon->SetToolTip(WeaponToolTipWidget);
    }

     

    여기가 이제 환장스러운(?) 부분입니다.. 

    if(WeaponToolTipClass == nullptr)  return;
        WeaponToolTipWidget = CreateWidget<UWeaponTooltipWidget>(this, WeaponToolTipClass);
        if(WeaponToolTipWidget == nullptr)  return;
    const auto dataItem = this->player->itemInventory[slotNum];

     

    이부분은 위젯을 생성해주는 부분이고, 이 슬롯에 해당되는 플레이어의 인벤토리 슬롯의 아이템 정보를 담아옵니다. 

    이 코드 아랫부분은 이제 전부 아이템의 정보를 툴팁에 담아주는 부분입니다만... 대부분의 무기 스탯이 정수 또는 실수라서 이것을 하나하나 FText로 변환하면서 코드가 무식하게 길어지고 말았습니다. 대환장 파티 그 자체입니다. 

     

    icon->SetToolTip(WeaponToolTipWidget);

     

    마지막으로 인벤토리의 아이콘에 마우스 커서를 대면 이 툴팁이 떠오르도록 SetToolTip함수를 이용하여 등록시켜줍니다. 이것은 제공되는 함수이므로 제가 구현한 것이 아닙니다. 

     

     

     

    그리고 방금 툴팁 위젯 클래스를 기반으로 만든 툴팁 UI입니다. 정말 허접해서 부끄럽지만 제가 디자이너는 아니니.. 나중에 다른 UI 이미지를 구할 수 있다면 교체해야겠습니다.

     

     

     

     

    USlotUI 블루프린트에 아까 만든 툴팁 블루프린트를 등록시켜두고 실행해보면

     

     

     

    이렇게 마우스 커서를 올렸을때 툴팁이 작동하는것을 확인할 수 있었습니다. 다만 문제가 있다면 아이템을 이동시켰을때 비워진곳에도 툴팁이 계속 남는 버그가 있는데요. 이건 나중에 어떻게든 고쳐봐야겠습니다. 

     

    이만 줄이겠습니다. 이번주에 시간이 얼마나 있을지 모르겠지만, 짬짬히 개발을 해나가도록 하겠습니다. 감사합니다. 

Designed by Tistory.