【UE5】UnrealPythonでシーケンサーを扱うTips

プログラマーの尾関です。

前回の【UE5】UnrealPythonの基本的な使い方に続いて、今回はシーケンサをUnrealPythonで扱う時のTipsをまとめてみました。

目次

シーケンサーの作成・削除

レベルシーケンスの作成

以下はコンテンツフォルダ直下に “SQ_Test” という名前でレベルシーケンスを作成するサンプルです。

import unreal

## AssetToolsを取得.
tools:unreal.AssetTools = unreal.AssetToolsHelpers.get_asset_tools()

## コンテンツ直下に "SQ_Test" という名前で 新規作成.
level_sequence:unreal.LevelSequence = tools.create_asset(
    asset_name     = "SQ_Test"
    , package_path = "/Game/"
    , asset_class  = unreal.LevelSequence
    , factory      = unreal.LevelSequenceFactoryNew()
)
Information

すでに作成済みの場合は以下の削除確認(上書き確認?)メッセージが表示されます。

このメッセージを表示したくない場合は、あらかじめ EditorAssetLibrary.delete_asset() でシーケンサーを削除しておきます。

削除

アセットの削除は EditorAssetLibrary.delete_asset() で行います。

import unreal

## "SQ_Test" を削除する
if unreal.EditorAssetLibrary.delete_asset("/Game/SQ_Test"):
    print("削除成功")
else:
    print("削除失敗 (存在しないかパスを間違えている)")
Warning

特に確認ダイアログの表示なしで削除されるので注意してください

基本情報の編集

フレームレートの設定

レベルシーケンスのデフォルトのフレームレートは “30 fps” なのですが、これを “60 fps” に修正してみます。

level_sequence:unreal.LevelSequence

# フレームレート設定
fps:int = 60 # 60 FPS
level_sequence.set_display_rate(unreal.FrameRate(60))

60FPSになりました。

開始時間と終了時間の設定

開始時間から終了時間までの長さについて、レベルシーケンスのデフォルトは “5秒” となっています。

画像では 60fps なので、60fps x 5秒 = 300フレームとなっています。

これを1秒 (60フレーム) に変更してみます。

level_sequence:unreal.LevelSequence

# 開始時間と終了時間の設定.
## 開始時間の設定.
#level_sequence.set_playback_start(0) # フレーム数指定.
level_sequence.set_playback_start_seconds(0.0) # 秒指定.
## 終了時間の設定.
#level_sequence.set_playback_end(60 * 1) # フレーム数指定.
level_sequence.set_playback_end_seconds(1.0) # 秒指定.

実行すると以下のように60フレームが最大となりました。

なお、設定関数には以下のものがあります。

関数名説明
開始時間の設定set_playback_start()フレーム数指定で開始時間を設定する
set_playback_start_seconds()指定で開始時間を設定する
終了時間の設定set_playback_end()フレーム数指定で終了時間を設定する
set_playback_end_seconds()指定で終了時間を設定する

アクターへのバインド

アクターをSpawnしてバインドする

“BP_MyActor” というブループリントクラス (Actorを継承) をレベルシーケンスにバインドするサンプルです。

Information

このサンプルでは Spawn処理を行います

level_sequence:unreal.LevelSequence

# アクターをスポーンする.
## BPのアクタークラスを読み込む.
actor_class:unreal.Actor = unreal.EditorAssetLibrary.load_blueprint_class("/Game/BP_MyActor")
## 現在開いているレベルに配置する.
location:unreal.Vector = unreal.Vector()
rotator:unreal.Rotator = unreal.Rotator()
actor:unreal.Actor = unreal.EditorLevelLibrary.spawn_actor_from_class(actor_class, location, rotator)

actor_system:unreal.EditorSubsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
## レベルシーケンスにバインドする.
actor_binding:unreal.SequencerBindingProxy = level_sequence.add_possessable(actor)
unreal.LevelSequenceEditorBlueprintLibrary.refresh_current_level_sequence()

実行すると “BP_MyActor” がレベルシーケンスにバインドされました。

レベルに配置済みのアクターにバインドする

パスを指定する

パスを指定してバインドする場合のサンプル。

# レベルからアクターを取得する.
sub_system:unreal.EditorActorSubsystem = unreal.EditorActorSubsystem()
actor:unreal.Actor = sub_system.get_actor_reference("PersistentLevel.BP_MyActor_C_0")
if actor is None:
    print("BP_MyActorは存在しない")
    raise(Exception("error"))

## レベルシーケンスにバインドする.
actor_binding:unreal.SequencerBindingProxy = level_sequence.add_possessable(actor)
unreal.LevelSequenceEditorBlueprintLibrary.refresh_current_level_sequence()

パスを調べるにはエディタ上で選択して、 unreal.EditorActorSubsystem().get_selected_level_actors() で print() して確認するのが良さそうです。

for actor in unreal.EditorActorSubsystem().get_selected_level_actors():
    print(actor)

あえて関係ないオブジェクトを選択して出力するテストです。

■実行結果

LogPython: <Object '/Game/NewMap.NewMap:PersistentLevel.Floor' (0x0000097DAE6E5A00) Class 'StaticMeshActor'>
LogPython: <Object '/Game/NewMap.NewMap:PersistentLevel.BP_MyActor_C_0' (0x0000097DD0548200) Class 'BP_MyActor_C'>

選択しているアクターをバインドする

# レベルからアクターを取得する.
actor_system:unreal.EditorActorSubsystem = unreal.EditorActorSubsystem()
actors = actor_system.get_selected_level_actors()

## レベルシーケンスにバインドする. (最初のactorと想定)
actor_binding:unreal.SequencerBindingProxy = level_sequence.add_possessable(actors[0])
unreal.LevelSequenceEditorBlueprintLibrary.refresh_current_level_sequence()

トラック・セクションの作成

Transformトラックの追加

SequencerBindingProxy.add_track(unreal.MovieScene3DTransformTrack) で Transformトラックを追加できます。

事前にバインドした対象の子トラックを追加してみます。

## レベルシーケンスにバインドする. (最初のactorと想定)
actor_binding:unreal.SequencerBindingProxy = level_sequence.add_possessable(actors[0])

transform_track = actor_binding.add_track(unreal.MovieScene3DTransformTrack)

オーディオトラックの追加

level_sequence:unreal.LevelSequence

## AudioTrackを作成
audio_track:unreal.MovieSceneAudioTrack = level_sequence.add_master_track(unreal.MovieSceneAudioTrack)
## トラックの名前は "sfx"
audio_track.set_display_name("sfx")

マスタートラックに “sfx” という名前でオーディオトラックが追加されます(※サウンドリソースの指定方法は不明?)

イベントトリガーセクションの作成

level_sequence:unreal.LevelSequence

## レベルシーケンスにバインドする. (最初のactorと想定)
actor_binding:unreal.SequencerBindingProxy = level_sequence.add_possessable(actors[0])

## 「Event > トリガー」セクションを作成
event_track:unreal.MovieSceneEventTrack = actor_binding.add_track(unreal.MovieSceneEventTrack)
event_trigger:unreal.MovieSceneEventTriggerSection = event_track.add_event_trigger_section()

イベントトリガーセクションにキーを打つ

以下は、3フレーム目にキーを打つサンプルです。

## レベルシーケンスにバインドする. (最初のactorと想定)
actor_binding:unreal.SequencerBindingProxy = level_sequence.add_possessable(actors[0])

## 「Event > トリガー」セクションを作成
event_track:unreal.MovieSceneEventTrack = actor_binding.add_track(unreal.MovieSceneEventTrack)
event_trigger:unreal.MovieSceneEventTriggerSection = event_track.add_event_trigger_section()

for channel in event_trigger.get_all_channels():
    # チャンネルの型を設定.
    c:unreal.MovieSceneScriptingEventChannel = channel
    # イベント生成.
    ev = unreal.MovieSceneEvent()
    # フレーム数を設定.
    n:unreal.FrameNumber = unreal.FrameNumber(3)
    # キーを打つ.
    c.add_key(n, ev)

    break # 最初の1つだけと想定.

3フレーム目にキーが打たれました。

クイックバインドで関数を呼び出す

ここでは、Print Hello(str1, str2) をクイックバインドで呼び出すキーを打ってみます。

import unreal

## AssetToolsを取得.
tools:unreal.AssetTools = unreal.AssetToolsHelpers.get_asset_tools()

## "SQ_Test" を削除する
if unreal.EditorAssetLibrary.delete_asset("/Game/SQ_Test") == False:
    print("削除失敗 (存在しないかパスを間違えている)")

## コンテンツ直下に "SQ_Test" という名前で 新規作成.
level_sequence:unreal.LevelSequence = tools.create_asset(
    asset_name     = "SQ_Test"
    , package_path = "/Game/"
    , asset_class  = unreal.LevelSequence
    , factory      = unreal.LevelSequenceFactoryNew()
)

# フレームレート設定
fps:int = 60 # 60 FPS
level_sequence.set_display_rate(unreal.FrameRate(60))

# 開始時間と終了時間の設定.
## 開始時間の設定.
#level_sequence.set_playback_start(0) # フレーム数指定.
level_sequence.set_playback_start_seconds(0.0) # 秒指定.
## 終了時間の設定.
#level_sequence.set_playback_end(60 * 1) # フレーム数指定.
level_sequence.set_playback_end_seconds(5.0) # 秒指定.

# レベルからアクターを取得する.
actor_system:unreal.EditorActorSubsystem = unreal.EditorActorSubsystem()
actors = actor_system.get_selected_level_actors()

## レベルシーケンスにバインドする. (最初のactorと想定)
actor_binding:unreal.SequencerBindingProxy = level_sequence.add_possessable(actors[0])

## 「Event > トリガー」セクションを作成
event_track:unreal.MovieSceneEventTrack = actor_binding.add_track(unreal.MovieSceneEventTrack)
section:unreal.MovieSceneEventTriggerSection = event_track.add_event_trigger_section()

## チャンネルを取得.
channels:unreal.MovieSceneScriptingEventChannel = section.find_channels_by_type(unreal.MovieSceneScriptingEventChannel)

## クイックバインド.
quick_binding:unreal.SequencerQuickBindingResult = unreal.SequencerTools.create_quick_binding(
    level_sequence  # レベルシーケンス.
    , actors[0]     # バインドするオブジェクト.
    , "Print Hello" # バインドする関数.
    , False)        # call in editor.

## イベント生成.
payload = ["hoge", "piyo"] # 関数に渡す引数。バインドする関数と数が一致していなければいけない.
ev:unreal.MovieSceneEvent = unreal.SequencerTools.create_event(level_sequence, section, quick_binding, payload)

## フレーム数を設定.
n:unreal.FrameNumber = unreal.FrameNumber(3)

## キーを打つ.
channels[0].add_key(n, ev)

unreal.LevelSequenceEditorBlueprintLibrary.refresh_current_level_sequence()

クイックバインドで “Print Hello” を呼び出し、ペイロードで引数を渡すキーを打つことができました。

参考

今回の記事を書くにあたって以下の公式ドキュメントを参考にさせていただきました。

また、Unreal Engineをインストールした以下のフォルダにシーケンサー周りのサンプルコードがあります。

…\Engine\Plugins\MovieScene\SequencerScripting\Content\Python
  • sequencer_anim_examples.py: シーケンサー内のスケルトン アニメーションをアニメーション シーケンスとしてエクスポートするサンプル
  • sequencer_examples.py: ムービー録画のサンプル
  • sequencer_fbx_examples.py: シーケンサーの情報をもとにアニメーション情報付きのfbxを書き出すサンプル
  • sequencer_key_examples.py: セクションのキーを操作するサンプル

また以下の記事も参考にさせていただきました。

\ 最新情報をチェック /