【UE5・C++】SplineとSpline上を移動する床の実装

はじめに

次世代デジタル基盤開発事業部の安井です。
普段はスマートフォン向けのゲーム開発を主に行っております。
以前個人でUnrealQuestで参加をしたことがあるのですがSplineの機能の復習も兼ねてギミックの実装を行いました。 まとめたのはギミックとして実装したSplineとそれの上を移動する床です。
Splineを別の機能と組み合わせて様々なギミックなどに流用ができるので結構便利だなと感じています。 作成に関しては開発環境は下記を使用しました。

  • UE5.4
  • VisualStudio 2022

実装内容

実際にSpline上を移動する物体に関してあらかじめ下記の機能を予定して実装しました。

  • Spline上を等速で移動する
  • Spline終端まで移動したら始端箇所から移動するループ機能
  • Spline上の開始位置を指定して任意の位置から移動を開始させられる

上記の機能を満たして実装した結果下記gifのような形で動作しています。

ソースコード上の実装

今回実装したものは二つの機能で一つはSplineを元にした機能拡張でもう一つはその上を移動する床になります。 まずはレールのように乗せた床アクターが移動するためにクラスを作成します。 機能としてはSplineの長さを取得するための関数、Spline上の現在座標の算出関数、Spline上に存在するか判定の関数を設けています。
Spline上の現在座標の算出関数に関しては次に説明する移動する床から移動先の問い合わせを行います。

// 長さ取得
float AZipLineActor::GetSplineLength()
{
    return SplineComponent->GetSplineLength();
}

// 現在座標算出
FVector AZipLineActor::GetCurrentLocation(float Length, bool Loop)
{
    LocalLength = Length;
    // ループ時には移動先がSpline長より先の地点の場合には始端に戻る
    if (Loop) {
        LocalLength = fmod(Length, SplineComponent->GetSplineLength());
    }

    FVector Location = SplineComponent->GetLocationAtDistanceAlongSpline(LocalLength, ESplineCoordinateSpace::Type::World);

    return Location;
}

// Spline上にいるか判定
bool AZipLineActor::IsArrived(float Length)
{
    return SplineComponent->GetSplineLength() >= Length;
}

クラスの実装内容は一旦終わったので次は移動する床の方を実装します。
こちらではまずエディタ上で公開したい各種機能の公開設定を行なっています。 最初に決めたループ機能、開始位置を指定機能に関してはエディタ上から設定可能なようにしました。 また、等速移動に関してはテストプレイ時に調整できるようにエディタ上から変更可能にしました。
こちらが公開したパラメータで今回は全てZipLineという名前の項目でエディタ上で表示されるようにカテゴリをしました。

    // 移動開始座標
    UPROPERTY(EditAnyWhere, meta = (ClampMin = "0.0", ClampMax = "1.0"), Category = "ZipLine")
    float StartPoint = 0.0f;

    // 移動速度
    UPROPERTY(EditAnywhere, Category = "ZipLine")
    float Speed = 50.0f;

    // ループフラグ
    UPROPERTY(EditAnyWhere, Category = "ZipLine")
    bool bIsLoop = true;

移動する床の挙動は今回Tick関数毎に移動する作りにしました。
座標計算に関しては二段階に分けて実装しています。大まかな内容としてはTick関数ではSpline上を0~100%のどの位置にいるかを計算し、その後自作したSplineクラスに対して詳細な座標の算出の問い合わせを行っています。
まず1段階目のTick関数内では前回のTickで確定した座標と移動速度から次回の移動先を決めます。 加えて初期位置に移動させるために、初回のTick処理のみ公開したStartPoint割り当てSplineの長さに対してどれくらいの位置にいるかを別途算出します。 計算の都合上StartPointの指定は全体距離の内どこにいるか割合で指定し、始端を0%として終端の100%までをfloat型で0.0から1.0の間を指定可能にしています。 その後2段階目として自作のSplineクラスに対して現在位置の問い合わせを行います。位置が特定できたら戻り値を動く床の座標にセットして移動完了です。


void AScaffoldActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    MoveDistanceLocation = MoveDistanceLocation + DeltaTime * Speed;

    // 初回Tick時の床アクター配置箇所決定
    if (IsFirstTick) {
        MoveDistanceLocation = ZipLineActor->GetSplineLength() * StartPoint;
        IsFirstTick = false;
    }

    // 移動先座標の問い合わせ
    FVector SplineLocation = ZipLineActor->GetCurrentLocation(MoveDistanceLocation, bIsLoop);
    SetActorLocation(SplineLocation);
}

BP上での準備に関して

このままだとレベル上での表示物がないため該当クラスからブループリントを作成し、それぞれ実体部を用意します。 Splineに関してはSplineComponentを追加してDefaultComponentに割り当てます。ちょうど画像のようになるのでこれでこちらの作業は終了です。

次に動く床です。こちらは今回動く床の機能だけの実装となるためStaticMeshのみの配置でこちらもDefaultComponentに割り当てて画像のようにします。

その後StaticMeshを選択し詳細タブからStaticMeshに任意のMeshを割り当てます。

エディタ上での配置に関して

ここまでで準備が終わったので次は実際に配置を行います。まずSplineのを元としたBPを配置して任意の長さに形を変更していきます。 この際SplinePointを追加してあげることで任意の曲線や不規則な軌道で移動範囲を指定することができます。

次いで先ほど配置したBPと同一レベル上に動く床を配置します。 配置が終わったら動く床のZipLineActorにSplineを指定します。 任意でStartPointで移動開始位置、Speedで移動速度、Loopでループを行うかどうかを指定します。 最後にビューポート上で動作確認を行うなどして正常に動作を行えれば完成です。

まとめ

今回はSplineとSpline上を移動する床の実装を行いました。
元はグレイマンを固定して動かすジップラインの機能から移動部分を切り出して作った機能でした。 床を別のものに置き換えてSplineに沿わせて道や線路を配置することでシンプルな移動砲台や動く的など指定されたルートで動くギミックに流用が効くのでそれなりに利便性が高いのではないかと感じます。

テコテックの採用活動について

テコテックでは新卒採用、中途採用共に積極的に募集をしています。
採用サイトにて会社の雰囲気や福利厚生、募集内容をご確認いただけます。
ご興味を持っていただけましたら是非ご覧ください。 tecotec.co.jp