UnrealPythonでActorを生成する

UnrealEngine4でPythonを使ってアクターをスポーンする処理を書いたので。
確認バージョンは4.22です。

今回EditorAssetLibraryとEditorLevelLibraryを使用するのでPythonプラグインの他に「Editor Scripting Utilities」を有効にします。
f:id:kamitani_08:20190613122724p:plain

api.unrealengine.com

api.unrealengine.com

ざっと呼んでみた感じ EditorLevelLibrary の spawn_actor_from_object 関数でアクターを生成できるみたいなので
実験用にこんな感じのコードを書きました。

import unreal
asset = unreal.EditorAssetLibrary.load_asset("StaticMesh'/Game/StarterContent/Props/SM_Chair.SM_Chair'")
if asset:
	for x in range(10):
		for y in range(10):
			location = unreal.Vector()
			location.x = x * 100
			location.y = y * 100
			location.z = 300
			rotation = unreal.Rotator()
			spawnActor = unreal.EditorLevelLibrary.spawn_actor_from_object(asset, location, rotation)

実行結果
f:id:kamitani_08:20190613125211p:plain

意図したとおりに SM_Chair が100個生成されました。

Library系は下記のように調べればある程度良い感じの物が探せます。
api.unrealengine.com

はじめてのUnrealPython

UnrealEngine4でPythonが使えると聞いたのでとりあえず挨拶しておく
確認バージョンは4.22です。

適当なプロジェクトを作成し、Pythonプラグインを有効に
f:id:kamitani_08:20190613095401p:plain



helpを見た感じlog(str)でログ出力できるみたいなので
api.unrealengine.com


Pyファイルを作成してコードを書く
f:id:kamitani_08:20190613101238p:plain

「file->ExecutePythonScript」で作成したPyファイルを指定すると実行

やったぜ
f:id:kamitani_08:20190613100630p:plain

当たり前ですが、cmdに手打ちしても同じ結果が得られるので一回手打ちかコピペでcmdから実行した後に「↑->Enter」するとイテレーション早くて楽です
f:id:kamitani_08:20190613100713p:plain

ちなみにCmdのところをクリックするとPythonに切り替えられるのでその状態で「unreal.log("HelloWorld")」と打っても挨拶出来ます
f:id:kamitani_08:20190613102213p:plain

visual studio で開いているファイルを vim で開く方法

最近UE4を触っているとvisual studioを触る機会が多くなってきました。
その際にvisual studioで今開いてるファイルをvimでも開く方法がないかと調べてみたところ外部ツールに設定することで出来るようです。
code.msdn.microsoft.com

設定手順は以下。

外部ツールを作成

visual studio上でAlt+t、Alt+e、Alt+aの順番に押して新規外部ツールを作成して、下記の内容を追加

タイトル Vim
コマンド vim.exeへのパス
引数 --remote-send ":tabedit +$(CurLine) $(ItemPath)"
初期ディレクト $(ItemDir)
ショートカット設定

visual studio上でAlt+t、Alt+c、Alt+kの順番に押してキーボードショートカット設定まで行って設定した外部ツールを任意のキーに割り当てる(僕の場合はAlt+F1)
f:id:kamitani_08:20190509110631p:plain

これで終了です。
ちなみに上記設定だと先にvimを起動していないと正常に動作しないです。
もしvisual studio上でvimを立ち上げたいと思っている方がいるならば引数の部分を「+$(CurLine) $(ItemPath)」にすればファイル、行を指定してvimが開きます。

ではではよいvimライフを!!

プロパティ メタデータ指定子のメモ

UPROPERTYのmeta指定子の使用時の挙動などを備忘録も兼ねて書きます。
※この記事で検証していることは実際にそのmeta指定子の処理を見に行ったわけではないです。
 本記事で公式ドキュメントの記載とは違う動きをしている箇所がいくつかありますが、それがバグか筆者の使い方が間違えているのかの判断は各自検証してからしていただくようお願いします。(もし間違えてたら優しく教えてください!)

参考:Unreal Engine | メタデータ指定子



AllowAbstract

Subclass と SoftClass のプロパティで使用され、クラスピッカーで抽象クラス型を表示するかを指定することが出来ます。

たとえば:

UCLASS(Abstract,ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class TANKMYPROJECT_API UMyAbstractActorComponent : public UActorComponent
{
	GENERATED_BODY()
public:	
	// Sets default values for this component's properties
	UMyAbstractActorComponent();
protected:
	// Called when the game starts
	virtual void BeginPlay() override;
public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
};
UCLASS()
class TANKMYPROJECT_API UMyActorComponent : public UMyAbstractActorComponent
{
	GENERATED_BODY()
};

※1

UPROPERTY(EditAnywhere)
	TSubclassOf<class UMyAbstractActorComponent> Subclass_A;
UPROPERTY(EditAnywhere, meta = (AllowAbstract))
	TSubclassOf<class UMyAbstractActorComponent> Subclass_B;

class UMyAbstractActorComponent はUCLASSにAbstractを追加して抽象クラスにしています。
これを※1のように定義した場合結果は以下のようになります。
f:id:kamitani_08:20190423160932p:plain
f:id:kamitani_08:20190423160735p:plain



AllowedClasses

FSoftObjectPath プロパティで使われ、アセットピッカーに表示されるクラスを制限することが出来ます。

UPROPERTY(EditAnywhere, meta = (AllowedClasses = "World"))
	FSoftObjectPath World;
UPROPERTY(EditAnywhere, meta = (AllowedClasses = "Texture"))
	FSoftObjectPath Texture;
UPROPERTY(EditAnywhere, meta = (AllowedClasses = "Material"))
	FSoftObjectPath Material;
UPROPERTY(EditAnywhere, meta = (AllowedClasses = "Font"))
	FSoftObjectPath Font;
UPROPERTY(EditAnywhere, meta = (AllowedClasses = "DataTable"))
	FSoftObjectPath DataTable;
UPROPERTY(EditAnywhere, meta = (AllowedClasses = "MaterialInterface"))
	FSoftObjectPath MaterialInterface;
UPROPERTY(EditAnywhere, meta = (AllowedClasses = "World,DataTable"))
	FSoftObjectPath WorldAndDataTable;

こんな感じ
f:id:kamitani_08:20190423153535p:plain

WorldAndDataTableもばっちし
f:id:kamitani_08:20190423153653p:plain

ただAllowedClassesは自作のクラスや、一部クラスのには効かないみたいです。(4.22環境)

UPROPERTY(EditAnywhere, meta = (AllowedClasses = "ActorComponent"))
	FSoftObjectPath ActorComponent;

f:id:kamitani_08:20190427163833p:plain



AllowPreserveRatio

このプロパティを [Details (詳細)] パネルに表示するときに、ratio のロックが追加されます。
ロックすると、現在のxyzスケール値に基づいて均等に拡大縮小されるため、拡大縮小してもオブジェクトは各方向にその形状を維持します。

例:

UPROPERTY(EditAnywhere, meta = (AllowPreserveRatio))
	FVector Vector3 {};
UPROPERTY(EditAnywhere)
	FVector DefaultVector {};

f:id:kamitani_08:20190423164729p:plain


ArrayClamp

エディタ上で入力する値を 0 と配列のプロパティの名前の長さにクランプします。
配列サイズが0の場合は-1が入るようです。

UPROPERTY(EditAnywhere, meta = (ArrayClamp = "Array"))
	int32 Index{};
UPROPERTY(EditAnywhere)
	TArray<int> Array{};

ただ上記動画からもわかるようにArrayの要素数を変更した際にはIndexのClamp処理が行われず、エラーや警告も発生しないことに注意してください。


BlueprintCompilerGeneratedDefaults

Subclass と SoftClass のプロパティで使用されます。クラス ピッカーで Blueprint クラスのみを表示するかを示します。>公式より


ClampMin、ClampMax

どちらも float と integer のプロパティに使用され、ClampMin はプロパティに入力可能な最小値、ClampMax は最大値を指定します。

たとえば:

UPROPERTY(EditAnywhere, meta = (ClampMin = 5, ClampMax = 10))
	int Index{5};

こうすればIndex変更時にClampMin から ClampMaxまでの値にClampされます。
もちろんClampMin と ClampMax は単体でも使用可能です。



ConfigHierarchyEditable

このプロパティは、 config (.ini) ファイルにシリアル化されて、 config 階層のどこにでも設定することができます。>公式より


ContentDir

FDirectoryPath プロパティによって使用されます。このパスは、Content フォルダ内のスレート スタイルのディレクトリ ピッカーを使って選ぶことができます。>公式より
つまりこうゆう事

UPROPERTY(EditAnywhere, meta = (ContentDir))
	FDirectoryPath Directory_A;
UPROPERTY(EditAnywhere)
	FDirectoryPath Directory_B;

f:id:kamitani_08:20190423211901p:plain

Directory_Bの方だとエクスプローラーで指定する形になります。


DisplayName

エディタでの表示名を指定できます。

UPROPERTY(EditAnywhere, meta = (DisplayName="Index"))
	int hogehoge{1234};
UPROPERTY(EditAnywhere)
	int TestTest{};

f:id:kamitani_08:20190423212909p:plain


DisplayThumbnail

プロパティがアセット タイプであることを示し、選択したアセットのサムネイルを表示します。>公式より
たとえば:

UPROPERTY(EditAnywhere, meta = (DisplayThumbnail = "true"))
	UTexture2D* PaintTexture_A;
UPROPERTY(EditAnywhere ,meta = (DisplayThumbnail = "false"))
	UTexture2D* PaintTexture_B;

上記のようなコードを書くとこうなる。

f:id:kamitani_08:20190423214037p:plain
ちなみにデフォルトは(DisplayThumbnail = "true")の状態みたいです


EditCondition

このプロパティの編集を無効にするかどうかを示すために使うブール プロパティに名前を付けます。プロパティ名の前に "!" を付けるとテストが反転します。>公式より

たとえば:

UPROPERTY(EditAnywhere)
	bool bUseConstantValue{};
UPROPERTY(EditAnywhere, meta = (EditCondition = bUseConstantValue))
	float ConstantValue{};

上記のようなコードを書いた際には下記のように「bUseConstantValue == false」の際には ConstantValue は編集できなくなっているのがわかります。
f:id:kamitani_08:20190423215126p:plain



EditFixedOrder

ドラッグすることで配列の要素の順番が変わるのを防ぎます>公式より

UPROPERTY(EditAnywhere, meta = (EditFixedOrder))
	TArray<int> Array_A;
UPROPERTY(EditAnywhere)
	TArray<int> Array_B;

f:id:kamitani_08:20190423220333p:plain



ExactClass

AllowedClasses と合わせて FSoftObjectPath プロパティで使用されます。AllowedClasses で指定されているものと同じクラスだけを使用可能か、サブクラスも有効であるかを示します。>公式より

ちなみに:

UPROPERTY(EditAnywhere, meta = (AllowedClasses = "SkeletalMesh"))
	FSoftObjectPath SkeletalMesh_A;
UPROPERTY(EditAnywhere, meta = (AllowedClasses = "SkeletalMesh", ExactClass = "false"))
	FSoftObjectPath SkeletalMesh_B;

上記SkeletalMesh_AはSkeletalMesh_Bで宣言した時と同じ処理になります。


ExposeFunctionCategories

ブループリント エディタで関数リストを構築するときに関数を公開するカテゴリのリストを指定します。>公式より

たとえばこうゆう事です。

UPROPERTY( VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Components|SkeletalMesh"))
	class USkeletalMeshComponent* SkeletalMeshComponent_A;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
	class USkeletalMeshComponent* SkeletalMeshComponent_B;

f:id:kamitani_08:20190427172613p:plain


ただ今回検証した感じだと「関数を公開するカテゴリのリストを指定」しているかは関係ないみたいです。(4.22)

UPROPERTY( VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Components|SkeletalMesh"))
	class USkeletalMeshComponent* SkeletalMeshComponent_A;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = ""))
	class USkeletalMeshComponent* SkeletalMeshComponent_B;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories))
	class USkeletalMeshComponent* SkeletalMeshComponent_C;

f:id:kamitani_08:20190427172420p:plain




ExposeOnSpawn

このクラスのタイプで Spawn Actor ノードでこのプロパティを公開するかを指定します。>公式より
たとえばこうなります。

UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn))
	int Num_A{};
UPROPERTY(EditAnywhere, BlueprintReadWrite)
	int Num_B{};

f:id:kamitani_08:20190427174740p:plain



FilePathFilter

FFilePath プロパティによって使用されます。ファイル ピッカーで表示するパス フィルタを示します。共通の値として、"uasset" と "umap" 値を含みますが、他にも使える値があります。>公式より
たとえば:

UPROPERTY(EditAnywhere, Category = Automation, meta = (FilePathFilter = "uasset"))
	FFilePath FilePath_uasset;
UPROPERTY(EditAnywhere, Category = Automation, meta = (FilePathFilter = "umap"))
	FFilePath FilePath_umap;
UPROPERTY(EditAnywhere, Category = Automation, meta = (FilePathFilter = "*"))
	FFilePath FilePath_asterisk;

ここが変わります。(図はFilePath_uassetを選択した際の表示)
f:id:kamitani_08:20190427181039p:plain


HideAlphaChannel

FColor プロパティと FLinearColor プロパティで使用されます。詳細で、プロパティウィジェットを表示するときに Alpha プロパティが非表示になることを示します。>公式より
たとえば:

UPROPERTY(EditAnywhere)
	FColor Color_A {};
UPROPERTY(EditAnywhere, meta = (HideAlphaChannel))
	FColor Color_B {};

f:id:kamitani_08:20190427181755p:plain
上記コードだとこうなります。


カラーピッカーでもAlpha プロパティが表示になっていることも確認。
f:id:kamitani_08:20190427181928p:plain




HideViewOptions

Subclass と SoftClass のプロパティで使用されます。クラスピッカーで表示オプションを変更する機能を隠します。>公式より

UPROPERTY(EditAnywhere, meta = (HideViewOptions))
	FSoftClassPath SoftClass_A;
UPROPERTY(EditAnywhere)
	FSoftClassPath SoftClass_B;

f:id:kamitani_08:20190427183714p:plain



InlineEditConditionToggle

他のプロパティで切り替わり、単独では表示されない編集条件として、ブール プロパティはインラインでのみ表示されることを表します。>公式より
たとえば:

UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (InlineEditConditionToggle, ExposeOnSpawn))
	bool bFlag_A{};
UPROPERTY(EditAnywhere, BlueprintReadWrite)
	bool bFlag_B{};

このように書くとbFlag_Aは詳細には表示されません
f:id:kamitani_08:20190427185021p:plain

GetSetは通常通りに行えます。
f:id:kamitani_08:20190427185118p:plain




LongPackageName

FDirectoryPath プロパティによって使用されます。パスを長いパッケージ名に変換します。>公式より
どうやらパスを絶対か相対か切り替えることが出来ます。
たとえば:

UPROPERTY(EditAnywhere)
	FDirectoryPath DirectoryPath_A;
UPROPERTY(EditAnywhere , meta = (LongPackageName))
	FDirectoryPath DirectoryPath_B;

f:id:kamitani_08:20190427192031p:plain



あれ?



代入時に変換しているのかな?
f:id:kamitani_08:20190427192110p:plain
f:id:kamitani_08:20190427192159p:plain
変わらない....
LongPackageNameは機能していないのか...?(誰か教えて!!!


MakeEditWidget

Transform プロパティ、Rotator プロパティ、または Transforms、Rotators の配列で使用されます。移動可能なウィジェットとしてプロパティがビューポートに公開されることを示します。>公式より
これを指定することによってビューポート上にプロパティが表示されるようになります。

UE4 Textウィジェットの行間を調整する方法

既にTwitterでepicな猫の人がTextウィジェットの行間を調整する方法を紹介していたのだけど個人的な備忘録も兼ねて。

Textウィジェットの行間の調整は「Line Height Percentage」で可能。
f:id:kamitani_08:20190314010025p:plain

UE4 NiagaraModuleScriptの中にNiagaraModuleScriptを入れることが出来るのかを検証してみた結果出来なかった話

※この記事はUE4.21.1の物です

NiagaraModuleを作成していくうちに基底の親Moduleを継承した子Moduleという機能が欲しくなり、作れないか調べてみました。
結論から言うと現状Moduleの中にModuleを入れる事は出来ますがまったくと言って良いほど意味がありません、それにかなり使いづらいのでおススメもしません。

・おススメしない理由その1
Moduleパラメータの再帰的検索がされず、中で呼び出しているModuleにModuleパラメータが入っていた場合でもSelectedEmittersウィンドウには表示されません。
※ModuleWithModuleTestの中で呼び出しているModuleでModule.Color_001を設定しています。
f:id:kamitani_08:20181206173827p:plain
正直これがやりたかったので出来ないのはマジでつらいです...

・おススメしない理由その2
そもそもこれ関数にしたほうがまだ楽なのでは???
f:id:kamitani_08:20181206173724p:plain

・出来ること
Moduleパラメータでの編集は出来ないが、パラメータを参照し、値を書き換えることは可能
依存関係を作って入力と処理を分ければもしかするといい使い方があるかもしれない
(Moduleの依存関係の作り方についてはshiotani君がわかりやすくまとめてくれているのでそちらを参照してください)
saltcanyon.hatenablog.com



実際にやってみた

NiagaraModuleScriptを二つ作成し、名前を「Color_001UpdateTest」と「ModuleWithModuleTest」に変更
f:id:kamitani_08:20181206170128p:plain

Color_001UpdateTestの方から編集します。
MapGetにLinearColorを追加し「 Particles.Color_001」とリネーム、MapSetにParticles.Colorを追加しそれをつなぎます。
変化がわかるようにParticles.Color_001の値をR=1,G=0,B=0,A=1に変更します。
f:id:kamitani_08:20181206170207p:plain

次にModuleWithModuleTestを編集します。
先ほど作成したColor_001UpdateTestを追加します。
f:id:kamitani_08:20181206170219p:plain

確認
先ほど作成したModule確認用にエミッターを作成します。
テンプレートのSimpleSpriteBurstを作成。
f:id:kamitani_08:20181206170234p:plain

今回も前回同様、作成するModuleで色を設定するので不要になるColorModuleを削除。

今こんな感じ
f:id:kamitani_08:20181206170242p:plain

ParticleUpdateにModuleWithModuleTestを追加
f:id:kamitani_08:20181206170310p:plain

パーティクルの色はこんな感じ
f:id:kamitani_08:20181206170351p:plain

次に色を外部から操作出来るようにします。
エミッター側のパラメータにLinerColorを作成し「Particles.Color_001」とリネーム
f:id:kamitani_08:20181206170403p:plain
ModuleWithModuleTestの上でParticles.Color_001の値をR=0,G=0,B=1,A=1に変更します。
f:id:kamitani_08:20181206170412p:plain

変更した色がパーティクルに反映されました。
f:id:kamitani_08:20181206170445p:plain

まとめ
このようにModuleが使用できないだけでパラメータの参照は出来るのでまだ使い道があるかなと思ったのですが、
調べてみるとNiagaraFunctionScriptでも同じことが出来るみたいです。
f:id:kamitani_08:20181206173506p:plain
今後のアップデートでもしかすると再帰的なModuleパラメータの検索が実装されるかもしれませんが、今のところ基底Moduleみたいな事は出来ず、処理をまとめたい場合はNiagaraFunctionScriptでまとめるか諦めてコピペするしかなさそうです。
ところでこのModuleの処理は仕様なのかそうでないのかを判断できる場所って今のところあるんですかね?
もし知っている方がいらしたらコメントとかで教えていただけるとありがたいです。

【Niagara】自作したModuleのパラメータにデフォルトでDynamicInputを設定する方法

※この記事はUE4.21の物です。

Moduleを作成している際に地味にハマったのでメモ

やりたいことはこんな感じ
f:id:kamitani_08:20181203184014p:plain

このDynamicInputさん達を毎回決まっているのにイチイチ設定するのがめんどくさいので、Module作成時にデフォルトで設定したい。

というわけで早速作成してみる。

[準備]
まずModule確認用にエミッターを作成します。
テンプレートのSimpleSpriteBurstを作成。
f:id:kamitani_08:20181203184256p:plain
Moduleで変更された色の確認をしたいのでMaxLoopCountの値を0に変更
今回作成するModuleで色を設定するので不要になるColorModuleを削除。

今こんな感じ
f:id:kamitani_08:20181203184512p:plain

次にNiagaraModuleScriptを作成し、SelectedEmittersウィンドウからパーティクルの色を変えられるようにするため、
LinearColorを作成し「Module.Color」にリネームしてMapSetに繋げ、追加された変数の名前を「Particles.Color」にリネームする。
次に行うModuleが変更を適用しているかの確認用にModule.ColorのRの値を100に設定する。
f:id:kamitani_08:20181203191009p:plain

ParticleUpdateに作成したModuleを追加。

この時点でのパーティクルの色はこんな感じ
f:id:kamitani_08:20181203184622p:plain

設定した色が出てるのが確認できますね。
このColorパラメータにDynamicInputを設定していきます。

[ここから本番]

最初にBeginDefaultsノードを追加してその先にDynamicInputの「SplitLinearColor」を追加してModule.Colorに繋げます。
f:id:kamitani_08:20181203184723p:plain
この時作成されたModule.R、Module.G、Module.B、Module.AがSplitLinearColorで分割後のパラメータです。
f:id:kamitani_08:20181203184741p:plain
これでSplitLinearColorが設定できました。
f:id:kamitani_08:20181203184817p:plain

次は分割したRとAに変更を加えます。
MapSetを作成してModule.R、Module.Aを追加します。
追加したパラメータのModuleの部分をSplitLinearColorに変更します。
f:id:kamitani_08:20181203185053p:plain

先ほどと同様にRに100、Aに1を入れて同じ色が出ているか確認します。
f:id:kamitani_08:20181203185148p:plain

※Emitter画面に戻った際にModuleで行った変更が反映されないことがあります。
その際は下記画像にある黄色矢印のボタンを押すとModuleに設定されているデフォルトの状態に戻すことが出来るのでそれを押して更新しましょう。
f:id:kamitani_08:20181203185208p:plain

次に同じ要領でR要素にSineを設定していきます。
f:id:kamitani_08:20181203185237p:plain


最後にB要素にSineを設定します。
自分はここで少しハマったのですが、
Sineを追加する際に元からあるノードをコピペして持ってくると同じ名前のSineノードが作成されます。
f:id:kamitani_08:20181203185508p:plain

このノード、リネームもできないしこの状態だと各Sineに別々のパラメータを入れることが出来なくて少し悩ました。
解決方法としては素直に左クリックからSineを追加するとSine001が作成されて区別することが出来ます。
f:id:kamitani_08:20181203185437p:plain