このページでは、Unreal Editor で Python の使用を開始する方法について説明します。
Python を使用する理由
近年 Python は、特にメディアやエンターテイメント業界において制作パイプラインや 3D アプリケーション間の相互運用の場面で事実上の標準言語となりました。これは、幅広いジャンルのアプリケーションでサポートされるようになったことが主な理由です。制作パイプラインが複雑さを増し、使用するアプリケーションの数も増加していく中で、共通のスクリプト言語を持つことにより大規模なアセット管理システムの構築および維持が容易になります。
このような外部事情や他のアプリケーションとの作業の必要性を考慮する必要がない場合にも、Unreal Editor 内におけるワークフローの自動化を検討する際に Python は優れた選択肢となります。プログラミング初心者でも比較的簡単に始めることができ、PySide のようなモジュールを使用して複雑かつ機能満載のユーザー インターフェースを作成できます。その他にも便利な無料モジュールがコミュニティ向けに多数公開されているため、それらを利用して作業の負担を軽減することができます。
Unreal Editor では、Python を使用して次のような作業が可能です。
- 大規模なアセット管理パイプラインや、組織で使用する他の 3D アプリケーションに Unreal Editor を結び付けるワークフローの構築。
- スタティック メッシュの詳細度 (LODs) の生成のように、時間がかかるアセット管理タスクの Unreal Editor における自動化。
- レベルでのコンテンツのプロシージャルなレイアウト。
- Python でユーザーが独自に作成した UI を使用した Unreal Editor の制御。
Python を使用するプロジェクトを設定する
Unreal Editor における Python のサポートは、Python Editor Script Plugin により提供されています。エディタで Python スクリプトを実行する前に、現在のプロジェクトでこのプラグインを有効にする必要があります。
現時点では、プロジェクトごとにプラグインを有効にする必要があります。
次の手順でプラグインを有効にします。
- プロジェクトを開き、メインメニューから [Edit (編集)] > [Plugins (プラグイン)] を選択します。
- [Plugins] ウィンドウの [Scripting] セクションに移動します。 右側のパネルにある [Python Editor Script Plugin] を確認し、[Enabled] ボックスをオン (有効) にします。 多くの共通するエディタのタスクに対して単純化された API を提供する Editor Scripting Utilities プラグインの有効化も必要になります。詳細については、「エディタのスクリプティングと自動化」を参照してください。
- エディターを再起動します。
Python 3.7.7
Python Editor Script Plugin には、組み込みバージョンの Python 3.7.7 が含まれています。
つまり、コンピュータに Python を別途インストールする必要はありません。
Unreal はデフォルトで Python 3.7.7 を使用します。これは、現在の VFX Reference Platform において Python 3.7.7 が重要な役割を担っているためです。Unreal Engine は Python 2.7 をサポートしますが、使用するときにエンジンでバージョンを変更する必要があります。
異なるバージョンの Python を使用する必要がある場合には、オペレーティング システムに UE_PYTHON_DIR
環境変数を設定して組み込むインストールを示し、次に Unreal Engine をソースから再ビルド します。
Unreal Editor で Python コードを実行する方法
Unreal Editor では、Python スクリプトをいくつかの異なる方法で実行することができます。それぞれが少し異なる使用状況に対して設計されているため、必要に応じて適切な方法を選択できます。
ブループリントとは異なり、Python 環境は Unreal Editor 内 でのみ使用可能です。Play In Editor、スタンドアローン ゲーム、クック済みの実行ファイルなど、いかなるモードであってもプロジェクトが Unreal Engine で実行されている場合は使用できません。つまり、Python はエディタのスクリプティングや自動化、アセット制作パイプラインのビルドでは自由に使用することができますが、現時点ではゲームプレイのスクリプト言語として使用することができません。
アウトプットログ内の Python コンソール
Unreal Editor のコンソール入力バーを切り替えると、Unreal のコンソール コマンドの代わりに Python コードを使用することができます。
この設定は、上の例のように [Output Log] パネルで切り替えるか、または「~
」キーを押してコンソール入力バーを表示させて切り替えることができます。
コンソールが Python モードの時は次の操作を実行できます。
- コマンド ウィンドウでインタラクティブな Python コンソールを使用する場合と全く同様に、一連の Python コードをこのコンソールに入力するとエディタが各ラインを即時実行する。これは Python コードをラインごとに実行する唯一の方法です。次に記載する他の方法はすべて、指定するスクリプト ファイルを実行します。
- Shift+Enter キーを押して各ラインを分けるか、またはテキスト エディタから複数のラインを持つブロックをコピーして貼り付けることにより、複数のラインで構成されているコードを一度に実行する。
- コンソールにファイル名を入力して Python スクリプト ファイルを実行する。Python スクリプトで追加のコマンドライン引数が必要な場合は、スクリプト名の後ろにそれらを含めます。
Python の組み込み print
関数による出力も [Output Log (アウトプットログ)] パネルにリダイレクトされます。
py コンソール コマンド
通常のコンソールでは、py
コマンドを使用すると上述のように Python コンソールに入力した場合と同様に残りのラインを Python コードとして実行できます。
たとえば、このコマンドでは指定したスクリプト ファイルを実行します。
エディタの起動時にこのコマンドを ExecCmd
コマンドライン パラメータの値で実行することは推奨しません。実行すると、エディタ環境の準備が整う前、たとえばスタートアップのレベルが完全にロードされる前にスクリプトが実行されます。より適切なオプションについては、以下のセクションを参照してください。
ファイル メニュー
Unreal Editorのメイン ウィンドウにある [File] メニューには、Python スクリプト ファイルの実行に使用できる新しいオプションが用意されています。
- 実行したことのないコンピュータ上の新しいスクリプト ファイルをブラウスするには、Execute Python Script (Pythonスクリプトを実行) を使用します。
- 以前実行したことがあるスクリプトを再実行するには、Recent Python scripts (最近のPythonスクリプト) リストを使用を使用します。ファイルはディスクから再読み込まれるため、前回実行した後にスクリプトを変更していた場合は新しいバージョンが実行されます。
コマンドライン
Unreal Editor をコマンドラインまたはスクリプトから起動する場合、コマンドライン引数で Python スクリプト ファイルを指定することができます。Python スクリプトで追加のコマンドライン引数が必要な場合は、スクリプト名の後ろにそれらを含めます。
コマンドラインから Python スクリプトを実行するには 2 つの異なる方法があります。どちらの方法でも、エディタは指定した Python スクリプトを実行するとすぐにシャットダウンします。
オプション 1:フル エディタ
この方法では、Unreal Editor が完全な状態で起動し、指定したプロジェクトを開いてデフォルトのスタートアップ レベルをロードします。すべてがロードされて準備が整うとすぐに Python スクリプトが実行されます。この方法は、プロジェクト内やロードに時間がかかるレベル内のコンテンツとのインタラクションが必要なスクリプトの場合に適しています。
コマンドラインに ExecutePythonScript
引数を追加し、その値を実行する Python スクリプトのパスとファイル名に設定します。次に例を示します。
> UE4Editor-Cmd.exe "C:\projects\MyProject.uproject" -ExecutePythonScript="c:\my_script.py"
この方法を使用する場合は、プロジェクトで Editor Scripting Utilities プラグインを有効にしておく必要があります。
コマンドラインで指定した Unreal Engine プロジェクトで、Python スクリプト プラグインをあらかじめ有効にしておく必要があります。
オプション 2:コマンドレット
この方法は高速で実行され、エディタ UI を表示しないヘッドレス モードでスクリプトを実行しますが、スクリプトでインタラクションが必要なレベルおよび他の種類のアセットのロードには注意が必要です。
コマンドラインに引数 -run=pythonscript -script=<script_file_or_code>
を追加します。<script_file_or_code>
には次のいずれかの値を使用します。
- 実行する Python スクリプトのパスとファイル名。
- 実行する Python ステートメントとコマンド。必要に応じて、文字列の改行をエスケープするために「\n」を使用できます。
次に例を示します。
> UE4Editor-Cmd.exe "C:\projects\MyProject.uproject" -run=pythonscript -script="c:\\my_script.py"
または:
> UE4Editor-Cmd.exe "C:\projects\MyProject.uproject" -run=pythonscript -script="a=5 \nb=10 \nc=a+b \nf=open('D:\myfile.txt','w+') \nf.write(str(c)) \nf.close()"
コマンドラインで指定した Unreal Engine プロジェクトで、Python スクリプト プラグインをあらかじめ有効にしておく必要があります。
init_unreal.py ファイル
エディタが「init_unreal.py」という名前のスクリプト ファイルを使用するように構成されているパスを検知すると (後述の「Unreal Editor の Python パス」を参照)、自動的にそのスクリプトを即時実行します。
この方法は、プロジェクトやプラグインで作業し、そのコンテンツの作業者全員がエディタの起動時に同じ初期化コードを実行する必要があるとわかっている場合に適しています。その場合は初期化コードをこの名前でスクリプト内に含め、作業のプロジェクトまたはプラグイン内の「Content/Python」フォルダに保存します。
スタートアップ スクリプト
[Project Settings (プロジェクト設定)] では、プロジェクトを起動するたびに実行する Python スクリプトをいくつでも指定することができます。エディタはデフォルトのスタートアップ レベルが完全にロードされた後、これらのスクリプトを実行します。
[Edit] > [Project Settings…] を選択し、次に [Plugins (プラグイン)] リストの下にある [Python] を選択します。そこで、スクリプトを [Startup Scripts] 設定に追加します。
設定が完了したら Unreal Editor を再起動します。次にエディタがプロジェクトをロードする際に、新しく追加したスタートアップ スクリプトが実行されます。
エディタ専用のブループリント
Python スクリプト プラグインでは、ブループリント グラフの評価中に Python コードのスニペットまたはファイルの実行に使用できるブループリント ビジュアル スクリプティングに新しいノードを公開します。
Python の実行ノードは、Editor Utility Widgets や Editor Utility Blueprints のようなエディタ専用のブループリント クラスでのみ使用可能です。詳細は、「ブループリントを使用したエディタのスクリプティング」を参照してください。アクタ から直接取得するクラスのように、ランタイム時に使用可能なブループリント クラスでは、このメソッドを使用できません。
次のノードが [Blueprint (ブループリント)] パレットの [Python] > [Execution] セクションに表示されます。
Execute Python Script | Python Command の入力に渡した、または打ち込んだリテラル Python コードを実行します。ブループリントから Python を呼び出すための推奨される方法で、Python で新しい BlueprintFunctionLibrary(BPFL) 型を作成する代わりになります。
このノードではファイルを実行することができません。Python コードのラインのみを実行します。 |
|
Execute Python Command | [Python Script] の入力に渡した、または打ち込んだリテラル Python コードやファイルを実行します。ノードは入力に基づき、それがリテラル コードかファイル名かを判断しようとします。 Python コードまたはファイルの実行に成功すると、Return Value 出力は「true」となります。失敗した場合は「false」が返されます。false の場合、[Output Log (アウトプットログ)] でエラーを確認することができます。 |
|
Execute Python Command (Advanced) | Python Script 入力に渡した、または打ち込んだリテラル Python コードやファイルを実行します。このノードは Execute Python Command に似ていますが、いくつかのシナリオで役に立つ追加入力や出力を提供します。
|
Unreal Editor の Python パス
上述のメソッドを使用して Python スクリプトを実行する、またはスクリプトの import
コマンドを使用して別のスクリプト モジュールをインポートする際に相対パスを使用する場合、実行またはインポートするスクリプトを Python 環境の sys.path
変数にリストされているいずれかのパスに含めることができます。
Unreal Editor では、この sys.path
リストにいくつかのパスを自動的に追加します。
- プロジェクトのフォルダの下にある「Content/Python」サブフォルダ。
- Unreal Engine のメインのインストール フォルダの下にある「Content/Python」サブフォルダ。
- 有効にした各プラグインのフォルダの下にある「Content/Python」サブフォルダ。
- ユーザー ディレクトリ内にある「Documents/UnrealEngine/Python」フォルダ。たとえば、Windows 10 では「
C:/Users/Username/Documents/UnrealEngine/Python
」となります。
また、このリストには次に挙げる方法のいずれかで独自のパスを追加することもできます。
- [Project Settings (プロジェクト設定)] で、[Edit] > [Project Settings…] を選択し、次に [Plugins (プラグイン)] リストの下にある [Python] を選択します。そこで、[Additional Paths] 設定にパスを追加します。設定が完了したら Unreal Editor を再起動します。
PYTHONPATH
環境変数の値にパスを追加したら Unreal Editor を再起動します。- Python スクリプト内の
sys.path
リストまたは Python コンソールに直接パスを追加します。
Unreal Editor の Python API について
Python Editor Script Plugin では、Unreal Editor、プロジェクトのアセット、レベル内のコンテンツとのインタラクションに使用できる幅広いクラスおよび関数が公開されています。この API はすべて unreal
モジュールに含まれています。API にアクセスするには、エディタの Python 環境で実行するいずれかの Python スクリプトの冒頭でこのモジュールをインポートします。
import unreal
unreal
モジュールでは、エディタ環境で C++ からブループリントに公開されるほぼすべてのものを公開しています。これは事前には生成されず、エディタのブループリントで使用可能なものすべてが自動的に反映されます。Unreal Editor で新しいプラグインを有効にすると、それらのプラグインによりブループリントに公開されるものはすべて Python でも使用可能になります。プロジェクトで作成してブループリントに公開する C++ コードについても同様です。
Python API では、Unreal のネイティブ API の公開について Python 開発者ができる限り容易に行える方法を提供しています。次に例を示します。
- シンプルなデータ タイプの Python とネイティブ タイプ間の変換は、必要に応じて透過的に実行されます。 Python のリスト (list)、セット (set)、または辞書 (dict) を渡す時、それらは自動的に Unreal の配列 (array)、セット (set)、またはマップ (map) に変換されます。API 関数によって返されたリスト、セット、または辞書を取得すると、実際には Unreal クラスのインスタンスを取得しますが、その API はベースとなる Python のリスト、セット、または辞書タイプと完全に一致します。
- Python クラスは、それらが表すネイティブ タイプと同じ継承階層を維持します。これはつまり、たとえば、ビルトインの Python 関数である
isinstance()
とtype()
を使用してオブジェクトが指定したクラスから派生したのか、あるいはそのクラスと一致するのかをテストできるということです。 - API は C++ および ブループリントに対して Unreal で使用する命名規則と Python の命名規則との間で良好なバランスを取ることができます。Python API のクラスおよびオブジェクトは、ブループリントにおける名前と同じ名前を持つことができます。これは通常、プレフィックス (たとえば
U
やT
など) を省略したネイティブ タイプと同じです。関数およびプロパティ名は、自動的に小文字のsnake_case
で公開されます。たとえば通常、関数は「unreal.StaticMeshActor.get_actor_transform()
」のように呼び出します。列挙型の値名は自動的に大文字のSNAKE_CASE
で公開されます。 - 公開された関数はすべて、順序付けされたパラメータ、または順序を問わない名前付けされたパラメータを受け入れることができます。たとえば、次の 2 つの関数呼び出しは全く同じことを行っています。
unreal.EditorLevelLibrary.join_static_mesh_actors(list_of_actors, my_options)
unreal.EditorLevelLibrary.join_static_mesh_actors(join_options=my_options, actors_to_join=list_of_actors)
API リファレンス
Unreal Python API によって公開されるすべてのクラスおよび関数の詳細については、
「Unreal Editor Python API リファレンス」を参照してください。
API リファレンスは、プラグインによって Python に公開されているものすべてを網羅しているリストではありません。API リファレンスに含まれていない追加プラグインをインストールし、そのスクリプティング機能が Python に公開される方法を確認する必要がある場合は、必要なプラグインのドキュメントを含む独自のローカル版 API リファレンスを作成します。この手順については、Unreal Engine のインストール フォルダ内の「Engine\Plugins\Experimental\PythonScriptPlugin\SphinxDocs」にある readme ファイルを参照してください。
Python API を使用するためのベスト プラクティス
このセクションでは、Python API を使用する際に留意する必要がある重要事項をいくつか紹介します。
アセットを使用して作業する
プロジェクトでアセットを使用して作業する必要がある場合は、必ず Unreal Python API の関数を使用します。Python にビルトインされているファイル管理モジュールを使用してディスク上のアセット ファイルを直接作業しないでください。たとえば、アセットを異なるフォルダに移動させる必要がある場合に os.rename
または shutil.move
のような Python 関数を使用しないでください。Unreal プロジェクトおよびアセットには内部コンテンツの参照が含まれているため、このルールに準拠しない場合はそれらが破損する可能性があります。
代わりに、Editor Scripting Utilities プラグインにより提供されている unreal.EditorAssetLibrary
API、またはUnreal Python API にビルトインされている unreal.AssetTools
クラスの使用を推奨します。
エディタのプロパティを変更する
Python を使用すると、プロジェクトのオブジェクトへのアクセスを取得し、それらのオブジェクトの多数の設定プロパティをプログラム的に設定することができます。たとえば、Python スクリプトでは現在のレベルにあるスタティック メッシュ アクタにアクセスし、アクタがダメージを受けるかどうか、また、ゲーム内で非表示にするべきかどうかなどのプロパティを設定できます。または、スタティック メッシュ コンポーネントを取得し、そのライトマス設定やリンクされているスタティック メッシュ アセットなども含めたコンポーネントのプロパティを設定できます。
これらのプロパティは、次の 2 つの方法で Python に公開することができます。
- BlueprintReadOnly または BlueprintReadWrite フラグの付いたアイテムは、オブジェクトのシンプルなプロパティとして公開されます。 これらのプロパティは、Python オブジェクトのプロパティにアクセスするのと同じように読み込み、変更することができます。
- ViewAnywhere または EditAnywhere フラグの付いたアイテムは、「エディタ プロパティ」として公開されます。
これらの値を読み込んだり書き込んだりするには、すべてのオブジェクトにより公開されている関数(
set_editor_property()
およびget_editor_property()
) の特別なペアを使用します。
各クラスの API リファレンスには、クラス説明のすぐ後に エディタ プロパティ のリストが記載されています。それらはすべて、この set_editor_property()
および get_editor_property()
関数を使用して設定および取得することができる値です。オブジェクトの設定プロパティを設定または取得する必要がある場合は、まず初めにこのリストに目的のプロパティが記載されているかを確認します。
- 通常、オブジェクト プロパティとエディタ プロパティの両方として公開されている値を読み込む必要がある場合、このプロパティに直接アクセスすることにより得られる結果は、
get_editor_property()
関数を呼び出して得られる結果と同じです。ただし、get_editor_property()
関数は Python オブジェクトで直接公開されていないプロパティにもアクセスする場合があります。 - オブジェクト プロパティとエディタ プロパティの両方として公開されている値を設定する必要がある場合、オブジェクトの値を直接設定するのではなく通常は
set_editor_property()
関数を使用して設定してください。UI でプロパティを調整すると、多くの場合にエディタはバックグラウンドで追加の処理(編集前および編集後の変更) を行います。これらの処理は通常、作業の途中で行った選択に対応するもので、エディタ画面とゲーム ワールド内のオブジェクトの状態を同期しています。Python オブジェクトでこれらのプロパティを直接変更すると、このエディタ コードが自動的に実行されなくなります。一方、set_editor_property()
を呼び出してプロパティの状態を設定すると、エディタ画面の [Details (詳細)] パネルで設定を変更した場合と全く同じように編集前および編集後のコードがトリガーされます。
たとえば、メディア プレーヤー オブジェクトには [Play on Open] 設定があります。
これは、play_on_open
クラス メンバーの unreal.MediaPlayer
クラスで公開されます。
import unreal
obj = unreal.MediaPlayer()
# Modifying a property directly can have different results
# than changing settings in the Editor UI.
# Generally you'll want to avoid setting these values directly, like this:
obj.play_on_open = True
# This way of accessing the property will have exactly the same
# result as changing the setting in the Editor UI:
obj.set_editor_property("play_on_open", True)
# Both ways of reading the value are equivalent.
# When a class exposes a property in both ways, you can use either:
play_value = obj.play_on_open
play_value = obj.get_editor_property("play_on_open")
可能な場合は Unreal 型を使用する
演算操作や 3D 座標の操作など、Unreal Python API で使用可能なユーティリティが必要な場合は、独自に実装したものを使用するのではなく、Unreal ユーティリティを使用することを推奨します。Unreal 版は、エンジン環境において最高のパフォーマンスを発揮するように最適化されています。
たとえば、3D 空間の座標を操作する必要がある場合に unreal.Vector
クラスを使用します。
import unreal
v1 = unreal.Vector()
v1.x = 10
v2 = unreal.Vector(10, 20, 30)
v3 = (v1 + v2) * 2
print(v3)
ログおよびフィードバック
unreal
オブジェクトはコードで使用できる関数を公開し、すべてのエンジンおよびエディタのサブシステムで使用されているものと同じメッセージング システムを介してログ、警告、およびエラーメッセージを送信します。このスクリプトでユーザーにメッセージを送信する必要がある場合は、常にこの標準化されたログ フレームワークを使用することを推奨します。
- 情報メッセージの場合は
unreal.log()
を使用します。利便性を図るため、Python のprint()
関数もunreal.log()
を内部でパススルーするために実装されています。 - 潜在的な問題をユーザーに警告する場合は
unreal.log_warning()
を使用します。 - 期待されるスクリプトの実行を妨げる深刻な問題の場合は
unreal.log_error()
を使用します。
メッセージは [Output Log] パネルに他のサブシステムから送信されたメッセージとともに表示されます。
アンドゥとリドゥのサポート
スクリプトでは、Unreal Editor にビルトインされている Undo (アンドゥ) / Redo (リドゥ) システムをフル活用することができます。
定義する トランザクション ごとに、Python の操作をいくつでも含めることができます。これらのトランザクションを使用すると、大規模な操作や多数の異なるオブジェクトに対する操作を [Undo] / [Redo] の履歴に 1 つのエントリとしてまとめることができます。スクリプトを使用して複数のオブジェクトに対して特定の変更を加える場合、通常は [Undo] / [Redo] 履歴のエントリを変更のたびに分けて記録せず、1 つのエントリとしてまとめることですべてのオブジェクトに対する変更をすべて元に戻すことが可能になります。
トランザクションの定義には、unreal.ScopedEditorTransaction
スコープを使用します。たとえば、次のコードを実行するとします。
import unreal
obj = unreal.MediaPlayer()
with unreal.ScopedEditorTransaction("My Transaction Test") as trans:
obj.set_editor_property("play_on_open", True)
obj.set_editor_property("vertical_field_of_view", 60)
その結果、エディタの [Undo History (元に戻す操作の履歴)] パネルにはトランザクションが名前順に一覧表示されます。
一般的なルールとして、スコープ済みのトランザクションにはエディタ画面で元に戻すことが可能な操作を含めることができます。ただし、すべてのエディタ操作が元に戻せるわけではありません。たとえば、エディタ画面でモデルをインポートすると元に戻すことができません。そのため、unreal.ScopedEditorTransaction
内でモデルをインポートしようとしても、期待どおりには実行されません。
遅い操作に対する進捗ダイアログ
1 つの操作で大量のアセットまたはアクタを作業する必要があるスクリプトの場合、完了までに時間がかかることがあります。Python スクリプトが実行されている間、Unreal Editor の画面はユーザーによるインタラクションがブロックされます。大規模なタスクの進捗情報をユーザーに提供し、エディタがフリーズまたは停止しているように見える状況を避けるため、unreal.ScopedSlowTask
スコープを使用することができます。
次に例を示します。
import unreal
total_frames = 100
text_label = "Working!"
with unreal.ScopedSlowTask(total_frames, text_label) as slow_task:
slow_task.make_dialog(True) # Makes the dialog visible, if it isn't already
for i in range(total_frames):
if slow_task.should_cancel(): #True if the user has pressed Cancel in the UI
break
slow_task.enter_progress_frame(1) # Advance progress by one frame.
# You can also update the dialog text in this call, if you want.
... #現在のフレームで作業できるようになりました。