LoginSignup
3
1

More than 5 years have passed since last update.

UE4 でプレイヤー以外の Tick と Physics を止める方法の検討 (第8回ぷちコン)

Last updated at Posted at 2017-10-01

はじめに

第8回ぷちコンにて実装した、 UE4 で自分のプレイヤー以外の時間(Tick,Physics)を止める方法を検討したときの覚書き。

参考までに応募したやつ ↓


http://www.youtube.com/watch?v=TMK2cYWaAyw

検討1: SetGamePaused → 不採用

SetGamePaused.png

これでは自分を含めて全部止まってしまう。
そもそもポーズ画面でこれを使うつもりだったので、不採用。

検討2: CustomTimeDilation + SetSimulatePhysics → 不採用

CustomTimeDilation.png

確かに、これで個別に Tick と物理を止めることは可能。
が、メッシュに対しては、個別に SetSimulatePhysics を呼ぶ必要がある。めんどくさい。
(事前に MeshComponent 検索して設定する機能をつけた BP を継承すれば良い話ではあるが)

あと、時間を止めるトリガーが来た瞬間に、ステージ内の自分以外の全アクターに対してこの処理が走ることになる。
うーん、もっとスマートな方法はないものか・・・。

検討3: UWorld::bPlayersOnly, UWorld::bShouldSimulatePhysics → 今回採用

実は、UWorld 内のプロパティをいじると、特定のアクター以外の時間を止めることができる

UWorld::bPlayersOnly

これを true にすると、ローカルでコントローラーに Possess されている APawn(もしくはその継承クラス, ACharactorとか) のみ Tick を走らせる ようになる。
もっと厳密にいうと、ワールドの TickType が強制的に ELevelTick::LEVELTICK_ViewportsOnly になる。
Actor が Tick による更新指示を受ける部分のコードを読めばわかるのだが、

Actor.cpp
void AActor::TickActor( float DeltaSeconds, ELevelTick TickType, FActorTickFunction& ThisTickFunction )
{
    //root of tick hierarchy

    // Non-player update.
    const bool bShouldTick = ((TickType!=LEVELTICK_ViewportsOnly) || ShouldTickIfViewportsOnly());
    if(bShouldTick)
    {
        // If an Actor has been Destroyed or its level has been unloaded don't execute any queued ticks
        if (!IsPendingKill() && GetWorld())
        {
            Tick(DeltaSeconds); // perform any tick functions unique to an actor subclass
        }
    }
}

// ~省略~

/** If true, actor is ticked even if TickType==LEVELTICK_ViewportsOnly */
bool AActor::ShouldTickIfViewportsOnly() const
{
    return false;
}

となっている。
つまり、アクターは基本的に ELevelTick::LEVELTICK_ViewportsOnly 時は Tick が走らない
しかし、AActor の継承クラスの一部において ShouldTickIfViewportsOnly() を override しているものがある。

  • ACameraRig_Crane
  • ACameraRig_Rail
  • ACineCameraActor
    • これらの3つはシーケンサ用で必ず true を返すようになっている。
  • APlayerCameraManager
    • APlayerController の参照を持っているときだけ true を返す。
    • APlayerController がスポーンされるときには必ず渡されるものなので、これも基本的には true を返すと見てよい
  • APawn
    • 「ローカルでコントロールされている」かつ 「APlayerController がセットされている」という条件で true を返す

ということで、自分で継承クラスを作って ShouldTickIfViewportsOnly() を override しない限りは、
カメラ関係以外ではローカルでコントローラーに Possess されている APawn かその継承クラスのみ Tick が走ることになる。

なので、これを true にすれば、プレイヤー以外の Tick を止めることができる。

UWorld::bShouldSimulatePhysics

これを false にすると、ワールドのすべての Physics による更新をしなくなる。
ただし、これはあくまで Physics の更新を止めるだけであり、オブジェクト同士の作用(ぶつかったときの力など)はそのまま受け付けている状態になる。
そのため、解除した瞬間に、蓄積された作用が一気に適用される挙動となる。

この挙動を起きないようにするためには、やはり SetSimulatePhyshics を false にしないといけない。
が、今回作ったゲームでは、むしろその挙動の方が面白かったので、あえてそのままにしてある。

実装

UWorld も上記のプロパティもブループリント公開はされてないので C++ で組む。
FunctionLibrary で共用の関数として、以下のようにして実装した。

CommonBlueprintFunctionLibrary.h
#include "Kismet/BlueprintFunctionLibrary.h"
#include "CommonBlueprintFunctionLibrary.generated.h"

UCLASS()
class ONEMINUTE_API UCommonBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()
public:

    UFUNCTION(BlueprintCallable, meta=(WorldContext="WorldContextObject") , Category="TimeStop")
    static void StartTimeStop(UObject* WorldContextObject);

    UFUNCTION(BlueprintCallable, meta=(WorldContext="WorldContextObject") , Category="TimeStop")
    static void FinishTimeStop(UObject* WorldContextObject);
};
CommonBlueprintFunctionLibrary.cpp
void UCommonBlueprintFunctionLibrary::StartTimeStop(UObject* WorldContextObject)
{
    UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);
    if(World) {
        World->bPlayersOnly = true;
        World->bShouldSimulatePhysics = false;
    }
}

void UCommonBlueprintFunctionLibrary::FinishTimeStop(UObject* WorldContextObject)
{
    UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);
    if(World) {
        World->bPlayersOnly = false;
        World->bShouldSimulatePhysics = true;
    }
}

あとは、ブループリントから必要なタイミングで呼び出せばよい。
やってみたときの実験動画 → https://ue4-mstdn.tokyo/@negimochi/1098

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1