UE5 で現在時刻を取得する時は Now や UTC Now のノードを使用しますが、取得できる値は DateTime 型です。 経過時間を求めたい場合や、何時間後の時刻を認める場合はここから何らかの加減算をする事になりますが、 UE4 までは時間を表わす TimeSpan 型との演算ノードが提供されていました。 ところが、UE5 になってから DateTime と TimeSpan との演算ノードがリストから削除されています。
これは UE5 から演算ノードのピンにワイルドカードが導入されたことが影響するようです。
DateTime と減算ノードのおかしな挙動
試しに加算ノードを出してみましょう。 Now ノードの DateTime 型のピンからドラッグして、"+"を入力すると、Add のノードがあります。
このノードを選択すると、加算ノードが出現し接続されます。 各ピンの型は、DateTime と TimeSpan を加算し DateTime を返すノードとなっています。
これを利用すると、例えばシステムのタイムゾーン設定に依らず JST の時間を計算する処理を書くことができます。
一方、減算ノードを出してみましょう。 Now ノードの DateTime 型のピンからドラッグして、"-"を入力すると、Subtract のノードがあります。
これを選択すると、なぜか減算ノードに接続されず、ワイルドカードのままになっています。なんでやねん!
もう一度ピン同士を接続してみます。再び Now ノードの DateTime 型のピンから減算ノードのピンにドラッグすると、 接続可能のチェックマークが表示されています。
マウスボタンを話すと、やはり接続されていません。なんでやねん!(2 回目)
ただ、減算ノードのピンの型が確定しているようなのでピンにマウスカーソルを重ねてみると、Timespan 構造体になっていることがわかります。
再び Now ノードの DateTime 型のピンからドラッグして減算ノードのピンに接続しようとすると、 今度はピンの型が違うため接続できない表示が出ます。そこは分かりますが、どうしてこうなった!
どうも UE5 の不具合のようで、すでに issues やフォーラムに投稿されています。
- UnrealEngine issues Subtraction Node wild card inputs incorrectly assigns Time Span data type when given a Date Time data type
- UnrealEngine Forum の投稿
解決策 1: プラグインを使う
結局のところどうすればいいのか調べたところ、マーケットプレースの無料プラグイン LE Extended Standard Library を 使うのがお手軽な気がします。
このプラグインには巨大な整数値を保持する LowEntry Long オブジェクトが実装されており、 DateTime から UNIX Timestamp(1970 年 1 月 1 日 0 時 0 分 0 秒からのミリ秒単位の数値)をこの LowEntry Long オブジェクトで取得することができます。 ここから任意の整数値の加減算が可能です。
経過時間の表示を実装する(UE4.27)
まずは UE4.27 で経過時間を表示する実装をしてみましょう。 Widget Blueprint を作成し、下記図のように Widget を配置します。
イベントグラフに下記図のように実装します。
Level Blueprint に Widget の作成処理を実装します。
PIE 実行し、Push ボタンを押すと下記図のように経過時間が表示されます。
経過時間の表示を実装する(UE5 + LowEntryExtStdLib)
同じ処理を UE5 でも実装してみましょう。
PIE 実行し、Push ボタンを押すと同様に経過時間が表示されます。
UE4.27 と同様に動作する事が確認できました。めでたしめでたし。
解決策 2: エディタ設定を変更する
この演算ノードのワイルドカードは Type Promotion という機能だそうで、エディタ設定で切ることができます。
演算ノードのワイルドカードが使えなくなりますが、DateTime - DateTime のノードが一覧に出てきます。
ただ、演算ノードのワイルドカード自体はそれはそれで便利なので機能ごと切ってしまうのは悩ましいですね…。
解決策 3: コピペ
実は DateTime - DateTime のノードは下記手順で表示することができます。
- UE4.27 で DateTime - DateTime のノードを表示し、コピーします。
- UE5 でペーストします。
このためにわざわざ UE4.27 をインストールするのが面倒…という方は、下記テキストを選択して UE5 にペーストしてみて下さい。
Begin Object Class=/Script/BlueprintGraph.K2Node_CallFunction Name="K2Node_CallFunction_2"
bIsPureFunc=True
FunctionReference=(MemberParent=Class'"/Script/Engine.KismetMathLibrary"',MemberName="Subtract_DateTimeDateTime")
NodePosX=736
NodePosY=448
NodeGuid=D7C304C4408C63BC8C8D2BA711817F71
CustomProperties Pin (PinId=4C2B8708470E5498F5334C82AF1BF2F5,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="Target\nKismet Math Library Object Reference",PinType.PinCategory="object",PinType.PinSubCategory="",PinType.PinSubCategoryObject=Class'"/Script/Engine.KismetMathLibrary"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,DefaultObject="/Script/Engine.Default__KismetMathLibrary",PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
CustomProperties Pin (PinId=3A5E5EDE4F4D6625332FD39051CE8503,PinName="A",PinToolTip="A\nDate Time Structure",PinType.PinCategory="struct",PinType.PinSubCategory="",PinType.PinSubCategoryObject=ScriptStruct'"/Script/CoreUObject.DateTime"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_VariableGet_6 7F10DB2647204613CAB646A6B79F0869,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
CustomProperties Pin (PinId=E0895CD44586D76CDEEDC6AED180B0BA,PinName="B",PinToolTip="B\nDate Time Structure",PinType.PinCategory="struct",PinType.PinSubCategory="",PinType.PinSubCategoryObject=ScriptStruct'"/Script/CoreUObject.DateTime"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_VariableGet_1 608475994F7AEA5402C76BB4688973EF,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
CustomProperties Pin (PinId=B99A9C8342C8EE2FFAD5328087841B82,PinName="ReturnValue",PinToolTip="Return Value\nTimespan Structure\n\nSubtraction (A - B)",Direction="EGPD_Output",PinType.PinCategory="struct",PinType.PinSubCategory="",PinType.PinSubCategoryObject=ScriptStruct'"/Script/CoreUObject.Timespan"',PinType.PinSubCategoryMemberReference=(),PinType.PinValueType=(),PinType.ContainerType=None,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PinType.bIsUObjectWrapper=False,LinkedTo=(K2Node_CallFunction_3 B5987E8A48EAE4775AEBCD9130085B18,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,bOrphanedPin=False,)
End Object
なんでやねん! (3 回目)