【UE4】ボックスコリジョンの操作性を向上させる


概要

なにかしらのイベントのトリガーとしてよく使われるBoxComponentですが、
サイズを変更したいとなった時にサイズの変更→サイズに合わせて位置を再結締という手順で作業しなければならず、
繰り返し微調整がしにくいなぁと感じていました。
頂点を引っ張って変形する形にできないかなと思い、実装してみました。
完成品としては以下のような感じです。

今回使用する仕組み

virtual void OnConstruction(const FTransform& Transform) override;
virtual void PostEditMove(bool bFinished) override;

UPROPERTY(EditAnywhere, Meta = (MakeEditWidget= true))
    FVector startPoint_;

UPROPERTY(EditAnywhere, Meta = (MakeEditWidget= true))
    FVector endPoint_;

OnConstructionはプロパティの値が変わるたびに呼び出される関数ですね。

PostEditMoveは移動完了時に呼ばれる関数で、後述の3DWidget機能にも有効です。
端折ってますが#if EDITOR_ONLY ~ #endifで囲う必要があります。

MakeEditWidgetはビューポート上で相対座標として表示してくれる機能です。
ビューポート上で選択し、つかんで移動することで値を変更することもできます。

実装としてはMakeEditWidgetによる移動でボックスの大きさ・位置を制御していきます。

実装

コードとしては以下のような感じです。

UCLASS()
class ABoxActor : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    ABoxActor();

    virtual void OnConstruction(const FTransform& Transform) override;

#if WITH_EDITOR
    virtual void PostEditMove(bool bFinished) override;
#endif

protected:

    UPROPERTY(VisibleDefaultsOnly)
        USceneComponent* rootScene_;

    UPROPERTY(VisibleDefaultsOnly)
        class UBoxComponent* boxComponent_;

    UPROPERTY(EditAnywhere, meta = (MakeEditWidget  = true))
        FVector startPoint_ = FVector(50.f);

    UPROPERTY(EditAnywhere, meta = (MakeEditWidget  = true))
        FVector endPoint_ = FVector(-50.f);

};
ABoxActor::ABoxActor()
{
    rootScene_ = CreateDefaultSubobject<USceneComponent>(FName(TEXT("RootScene")));
    {
        RootComponent = rootScene_;
    }

    boxComponent_ = CreateDefaultSubobject<UBoxComponent>(FName(TEXT("BoxComponent")));
    {
        boxComponent_->SetupAttachment(RootComponent);
        boxComponent_->SetBoxExtent(FVector(50.f));
    }

    PrimaryActorTick.bCanEverTick = false;
}

void ABoxActor::OnConstruction(const FTransform& Transform) 
{
    Super::OnConstruction(Transform);

    // 位置が変わるたびにボックスの大きさを変更
    if (startPoint_ + endPoint_ != FVector::ZeroVector)
    {
        const FBox box = FBox(startPoint_, endPoint_);
        boxComponent_->SetRelativeLocation(box.GetCenter());
        boxComponent_->SetBoxExtent(box.GetExtent().GetAbs());
    }
}

#if WITH_EDITOR
void ABoxActor::PostEditMove(bool bFinished) 
{
    // 移動が完了したら位置を修正する
    if (bFinished)
    {
        startPoint_ -= boxComponent_->GetRelativeLocation();
        endPoint_ -= boxComponent_->GetRelativeLocation();
        SetActorLocation(boxComponent_->GetComponentLocation());
        boxComponent_->SetRelativeLocation(FVector::ZeroVector);
    }
}
#endif

結果

ボックス判定のサイズ・位置調整がしやすくなります。
ぜひお試しください。
またより良い実装方法などありましたらご教授いただければと思います。