UE4 C++ InventorySystem Part.3 Chest

やあ

UE4 C++でインベントリシステムを作ろう! Part.3では、インベントリコンポーネントを持った、アイテムを作ってそれとやりとりできるようにするよ。

前回

pto8913.hatenablog.com

Part.3の結果

f:id:pto8913:20200502225815g:plain

目次

概要

①プレイヤー : アイテム(宝箱)を拾う
②宝箱 : 拾われた!イベント発生
③宝箱 : インベントリUIを開く
④プレイヤー : インベントリUIを開く
⑤終わり。

宝箱の動作を考える

・拾われたイベントの発生
-> インベントリUIを開く
これだけ!

拾われたイベントの発生、はPickUpableItemBaseクラスを作った時に見たよね。

宝箱の動作の実装

PickUpableItemBaseクラスを継承してChestItemBaseクラスを作成。
f:id:pto8913:20200501190210p:plain

宝箱のインベントリUIを表示させるためのUIをつくる

f:id:pto8913:20200501203527p:plain
イメージ図
これは宝箱だけじゃなく、例えば、敵を倒したあとに敵からアイテムを奪うみたいな時にも使える。
さらに、商人とアイテムをやり取りするような時にも使える。

WidgetBaseクラスを継承してExchangeInventoryBaseクラスを作る。
f:id:pto8913:20200501204208p:plain
ExchangeInventoryBase.hに追加

// Copyright(C)write by pto8913. 2020. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "UIs/Bases/WidgetBase.h"
#include "ExchangeInventoryBase.generated.h"

class AInventoryCharacterBase;

class UInventoryComponentBase;
class UBorder;

UCLASS()
class INVENTORYSYSTEM_API UExchangeInventoryBase : public UWidgetBase
{
    GENERATED_BODY()
private:
    UPROPERTY(meta = (BindWidget))
        UBorder* UpperBorder;

    UPROPERTY(meta = (BindWidget))
        UBorder* LowerBorder;
public:
    UPROPERTY()
        UWidgetBase* UpperUI;

    UPROPERTY()
        UWidgetBase* LowerUI;

    void OpenUI() override;
    void CloseUI() override;
};

ExchangeInventoryBase.cppに追加

// Copyright(C)write by pto8913. 2020. All Rights Reserved.

#include "UIs/Bases/ExchangeInventoryBase.h"
#include "UIs/Bases/InventoryWidgetBase.h"

#include "Characters/Bases/InventoryCharacterBase.h"

#include "Components/Bases/InventoryComponentBase.h"
#include "Components/Border.h"

//////////////////////////////////////
// Init

void UExchangeInventoryBase::OpenUI()
{
    UWidgetBase::OpenUI();

    UpperBorder->AddChild(UpperUI);

    LowerBorder->AddChild(LowerUI);
}


//////////////////////////////////////
// End

void UExchangeInventoryBase::CloseUI()
{
    UWidgetBase::CloseUI();

    UpperBorder->ClearChildren();

    LowerBorder->ClearChildren();
}

宝箱の動作の実装

ChestItemBase.h

// Copyright(C)write by pto8913. 2020. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Items/Bases/PickUpableItemBase.h"
#include "ChestItemBase.generated.h"

class UBoxComponent;
class UInventoryComponentBase;
class UExchangeInventoryBase;

UCLASS()
class INVENTORYSYSTEM_API AChestItemBase : public APickUpableItemBase
{
    GENERATED_BODY()
private:
    AChestItemBase();

    UPROPERTY(VisibleAnywhere)
        UBoxComponent* BoxCollisionComp;

    UPROPERTY(VisibleAnywhere)
        UInventoryComponentBase* InventoryComp;
private:
    /* UIs */
    UPROPERTY()
        UExchangeInventoryBase* ExchangeInventoryUI;
    /* Classes */
    UPROPERTY(EditAnywhere)
        TSubclassOf<UExchangeInventoryBase> ExchangeInventoryUIClass;
public:
    virtual bool PickUp(AInventoryCharacterBase* In) override;
};

ChestItemBase.cpp

// Copyright(C)write by pto8913. 2020. All Rights Reserved.

#include "Items/Bases/ChestItemBase.h"

#include "UIs/Bases/ExchangeInventoryBase.h"
#include "UIs/Bases/InventoryWidgetBase.h"

#include "Characters/Bases/InventoryCharacterBase.h"

#include "Components/Bases/InventoryComponentBase.h"

#include "Components/BoxComponent.h"
#include "Components/TextBlock.h"

AChestItemBase::AChestItemBase()
{
    BoxCollisionComp = CreateDefaultSubobject<UBoxComponent>(TEXT("Collision Comp"));
    BoxCollisionComp->SetupAttachment(RootComponent);

    InventoryComp = CreateDefaultSubobject<UInventoryComponentBase>(TEXT("Chest Comp"));
    InventoryComp->NumberOfSlots = 12;
}

bool AChestItemBase::PickUp(AInventoryCharacterBase* In)
{
    if (InventoryComp->Inventory.Num() == 0)
    {
        InventoryComp->Init();
    }

    if (IsValid(ExchangeInventoryUI) == true)
    {
        /* Close */
        InventoryComp->ToggleInventory();
        In->InventoryComp->ToggleInventory();
        In->bIsTalking = false;
        ExchangeInventoryUI->CloseUI();
        In->InventoryHUD->ExchangeBorder->SetRenderOpacity(0.f);
        In->InventoryHUD->ExchangeBorder->ClearChildren();
        ExchangeInventoryUI = nullptr;
    }
    else
    {
        ExchangeInventoryUI = CreateWidget<UExchangeInventoryBase>(
            GetWorld(), ExchangeInventoryUIClass
        );

        if (IsValid(ExchangeInventoryUI) == true)
        {
            InventoryComp->ToggleInventory();
            ExchangeInventoryUI->UpperUI = InventoryComp->InventoryUI;
            In->bIsTalking = true;
            In->InventoryComp->ToggleInventory();
            ExchangeInventoryUI->LowerUI = In->InventoryComp->InventoryUI;
            ExchangeInventoryUI->OpenUI();
            InventoryComp->InventoryUI->InventoryName->SetText(FText::FromString("Chest"));
            In->InventoryHUD->ExchangeBorder->SetRenderOpacity(1.f);
            In->InventoryHUD->ExchangeBorder->AddChild(ExchangeInventoryUI);
        }
    }

    return true;
}

エディタに戻って
ExchangeInventoryBaseクラスを継承して、WBP_ExchangeInventoryを作成。
f:id:pto8913:20200501211543p:plain

ChestItemBaseクラスを継承して、BP_ChestItemを作成。
f:id:pto8913:20200501231202p:plain
f:id:pto8913:20200501231417p:plain
今回は簡単にするため、二枚目の画像でインベントリにアイテムを手動で登録していますが、実際に使う際はランダムに決めたり、データテーブルで管理してください。

f:id:pto8913:20200502225815g:plain

今回はここまで

pto8913.hatenablog.com