UE4: UnrealWebServer Plugin が 1.4 にアップデート、機能追加& UE-4.18 対応
UE4 プロジェクトから簡単にウェブサーバーを建てるのに便利な UnrealWebServer プラグインがアップデートされました。今回の更新では開発元の IsaraTech. のなかの Thomas さんから「キミがリクエストしていた機能つけてアップデート公開したよ!」とお知らせを頂いたので、ドキュメントの更新が遅れているようで事実上現在はまだアンドキュメントだけど正式に最新版では使用可能になっている機能を簡単に紹介します。
Note: 有償のプラグインのためソースコードレベルでの変更の解説やdiffの紹介は行いません。
- サーバーに登録するハンドラー毎に
ExecuteInGameThread
フラグによりイベントを処理するスレッドを設定できるようになった。 Connection
に RAW 系メソッドが追加された。GetData
: 従来はGetGetVar
,GetPostVar
で key=value 群を前提としたリクエストボディーの取得しかできなかったが、新版では生のリクエストボディーを取得できるようになった。これにより、例えば POST で画像やzipなどの生のバイナリーを受け取ったり、テキストでも JSON を URL に対して直接投げて貰い受け取るなどの対応が可能になった。SendRawResponse
/SendRawResponseByte
: 従来はSendResponse
で文字列のレスポンスボディー、コンテントタイプヘッダー、クッキー、ステータスを返す事しかできなかったが、新板では生のレスポンス(ボディーではなく全体)を開発者が完全に任意に生成して返せるようになった。これにより、独自のヘッダーを返したり、その他ごにょごにょできるようなった。
次は「ハンドラーにワイルドカードか正規表現を使えるようにして Connection からリクエストされたパスを取得できるようにしてくれ」と要望してみる事にします😃
UE4: コンポーネントをアタッチする状況により潜む罠
今回紹介する「コンポーネントのアタッチ状況により潜む罠」は3つ以上のコンポーネントを"縦"にアタッチ(†)する場合に生じる可能性のある罠です。
例として、2つの USceneComponent
と1つの UStaticMeshComponent
を"縦"にアタッチする状況を幾つか挙げます。この様な状況は1つの AActor
の RootComponent
(=USceneComponent)と他の USceneComponent
と UAudioComponent
などでも同様です。
Note: この記事では煩雑を避ける目的でコード例から一般的な実装では組み込むがこの記事については直接関係しないエラーチェックなどを省きます。また、一般的には .cpp へ実装する cotr の実装も .h へ直接記述しています。
Case 1: すべて1つの ctor で CreateDefaultSubobject
で生成する場合
次のコード例のように関連するコンポーネントがすべて1つの ctor で生成されるような基礎的な実装では「罠」は生じません。
UCLASS() class AMyActor: AActor { GENERATED_BODY() public: AActor() { // Create; S2, M1 S2 = CreateDefaultSubobject< USceneComponent >( "S2" ); M1 = CreateDefaultSubobject< UStaticMeshComponent >( "M1" ); static ConstructorHelpers::FObjectFinder< UStaticMesh > m( TEXT( "/Game/MyMesh.MyMesh" ) ); M1->SetStaticMesh( m.Object ); // Attach; RootComponent, S2, M1 S2->SetupAttachment( RootComponent ); M1->SetupAttachment( S2 ); } USceneComponent* S2 = nullptr; UStaticMeshComponent* M1 = nullptr; };
ちなみに、 RootComponent
へ S2
をアタッチしてから S2
へ M1
をアタッチしようと、あるいは S2
へ M1
をアタッチしてから RootComponent
へ S2
をアタッチしようと、コンポーネントの SetStaticMesh
など準備を先に済ませてからアタッチしようと、アタッチした後でコンポーネントの準備を行おうと、何れも ctor を抜けた後の動作には変わりは生じません。それは罠にならないので1つ安心しましょう。
Case 2: すべて ctor 以外で NewObject
で生成する場合
次のコードのような場合も「罠」は"まだ"生じません。
// AMyActor.h UCLASS() class AMyActor: AActor { GENERATED_BODY() protected: void Tick( float ) override; public: USceneComponent* S2 = nullptr; UStaticMeshComponent* M1 = nullptr; };
// AMyActor.cpp void AMyActor::Tick( float ) { if ( something_trigger ) { // NewObject; S2, M1 S2 = NewObject< USceneComponent >( this ); S2->RegisterComponent(); M1 = NewObject< UStaticMeshComponent >( this ); M1->RegisterComponent(); M1->SetStaticMesh( Cast< UStaticMesh >( StaticLoadObject( UStaticMesh::StaticClass(), nullptr, TEXT( "/Game/MyMesh.MyMesh" ) ) ) ); // Attach; RootComponent, S2, M1 S2->SetupAttachment( RootComponent ); M1->SetupAttachment( S2 ); } };
Case 3: NewObject
で CreateDefaultSubobject
するコンポーネントを扱う場合
次の状況で「罠」が発生します。
- ctor で
CreateDefaultSubobject
によりUStaticMeshComponent
を生成し自らへアタッチするUSceneComponent
の派生クラスUMyScene
のようなものがある。 - ctor 以外で
NewObject
によりUMyScene
のオブジェクトS2
を生成し、S2
をRegisterComponent
し、RootComponent
へアタッチするAActor
の派生クラスAMyActor
のようなものがある。
言葉で書くとやや混乱するかもしれませんが、わりと簡単/単純で "ありそう" な状況です。
// UMyScene.h UCLASS() class UMyScene: USceneComponent { GENERATED_BODY() UMyScene() { // Create; M1 M1 = CreateDefaultSubobject< UStaticMeshComponent >( "M1" ); static ConstructorHelpers::FObjectFinder< UStaticMesh > m( TEXT( "/Game/MyMesh.MyMesh" ) ); M1->SetStaticMesh( m.Object ); // Attach; M1 -> this(≃S2) M1->SetupAttachment( this ); } // Create; this(≃S2) public: UStaticMeshComponent* M1 = nullptr; };
// UMyActor.h UCLASS() class AMyActor: AActor { GENERATED_BODY() protected: void Tick( float ) override; public: UMyScene* S2 = nullptr; UStaticMeshComponent* M1 = nullptr; };
// ****** TRAPPED ****** // AMyActor.cpp; void AMyActor::Tick( float ) { if ( something_trigger ) { // NewObject; S2, M1 S2 = NewObject< UMyScene >( this ); S2->RegisterComponent(); // Attach; RootComponent, S2, M1 S2->SetupAttachment( RootComponent ); } };
このように実装した AMyActor
の動作を確認すると、見えるはず、と意図したであろう UStaticMeshComponent
は見えません。存在するのに存在しません。
この罠を抜け出すための"ヒント"を示します。
// ****** AVOID TRAP ( DIRTY ) ****** // AMyActor.cpp; void AMyActor::Tick( float ) { if ( something_trigger ) { // NewObject; S2, M1 S2 = NewObject< UMyScene >( this ); S2->RegisterComponent(); // Attach; RootComponent, S2, M1 S2->SetupAttachment( RootComponent ); // ****** DIRTY IMPLEMENTATION ****** S2->M1->RegisterComponent(); } };
状況と必要な対応がわかりやすいように "DIRTY" な応急対処を示しました。
NewObject
で生成されるオブジェクトS2
が、- その
S2
の ctor においてCreateDefaultSubobject
で生成したオブジェクトM1
がある場合、 M1
はRegisterComponent
されていない。(ので、そうならない設計にするか、対処可能な実装を施す必要が生じる事がある)
という「罠」です・x・
もう少し複雑な状況でうっかりはまって気付かない事があると精神がすり減る事もありそうです。
Appendix
(†): 「"縦"にアタッチ」は Component0 へ Component1 をアタッチ、 Component1 へ Component2 をアタッチするような、1つのコンポーネントへ複数のコンポーネントをアタッチする状況を"横"、1つのコンポーネントへ1つのコンポーネントをアタッチし、アタッチしたコンポーネントへまた1つのコンポーネントをアタッチする状況を"縦"と模して表現したものです。
Component0 // コンポーネントの"横"の繋がり
- Component1
- Component2
- ...
Component0 // コンポーネントの"縦"の繋がり
- Component1
- Component2
- ...
- Component2
- Component1
References
UE4: 4.18 で追加された VSCode プロジェクト生成に少しだけ追加すると便利な事
1. launch.json
の <ProjectName>Editor (DebugGame)
の args
に -game
を追加する
UE4Editor
に -game
を追加して実行すると、 UE4Editor
の IDE のユーザーインターフェース類を表示せずに擬似的に直接プロジェクトのバイナリーを実行したのと同様の状態でデバッグ実行を開始できます。
この時、既存の起動中の UE4Editor のプロセスとは別のプロセスで実行できるので、 C++ コードの実装中にたまにある「もしかしたら落ちるかも」の確認を起動中の UE4Editor とは別に安全に行いつつ、わざわざデバッグ実行のためにIDEのユーザーインターフェースの表示などをスキップして実行できるので少し開発効率が良くなります。
2. launch.json
に Attach
プロファイルを追加する
既存の起動中の UE4Editor
にも VSCode からアタッチしてデバッグし、エディターの画面内でプレイ中に VSCode でブレークしてステップ実行するなどできます。以下のプロファイルを追加しておき、動作中の UE4Editor
へアタッチしたい場合に使います。
{ "name": "Attach" , "type": "cppvsdbg" , "request": "attach" , "processId": "${command:pickProcess}" }
アタッチの場合は、既に UE4Editor
が動いている状態でデバッグを即開始できるので、 -game
オプション付きであれ別プロセスで起動するよりもデバッグ開始までの所要時間がかかりません。但し、メインでブループリントやマテリアルを編集している UE4Editor
へアタッチしてデバッグ実行していても、アレなC++コードで落としてしまうとどうにもなりません。不安のあるコードや、落ちるバグをどうにかしたいデバッグ実行の際には(1)の -game
付きの別プロセス実行を行い、そうでもない場合には(2)で素早くアタッチしてデバッグすると捗るかもしれません。
UE4: 4.18 で VSCode に UE4Editor が対応したのでロストテクノロジーをメモしておく
Note: この記事は UE4Editor の公式対応で VSCode では不要になるロストテクノロジーについてメモするものです。 UE4Editor の VSCode 対応については参考1、参考2をどうぞ。
私はこれまでもVSCodeに幾つかのコマンドラインをカスタム定義して与えてUE4のプロジェクトをVSCodeで書いていましたが、全自動で .vscode に必要な定義を作ってくれるようになって楽で良いですね。
参考としてVSCodeでもVimでもUE4Editorが対応しないエディター環境やシェル直でコマンドラインしたい場合は次のように仕込みor叩きます。とりあえず .bat 風に紹介。
environment.bat // 共通の変数
set UNREALVERSIONSELECTOR="C:\Program Files (x86)\Epic Games\Launcher\Engine\Binaries\Win64\UnrealVersionSelector.exe" set UPROJECT="<path-to-uproject>.uproject" set BUILD="C:\Program Files\Epic Games\UE_4.18\Engine\Build\BatchFiles\Build.bat" set PROJECTNAME="<your-project-name>" set PROJECTNAMEEDITOR="<your-project-name>Editor"
genrate.bat: // 新しいソースを手追加したりした時に使う
call environment.bat %UNREALVERSIONSELECTOR% /projectfiles %UPROJECT%
build.debug.editor:
call environment.bat %BUILD% %PROJECTNAME% Win64 DebugGame %UPROJECT% -waitmutex
build.development.editor: // ほか editor なしや shipping も同様
call environment.bat %BUILD% %PROJECTNAMEEDITOR% Win64 Development %UPROJECT% -waitmutex
launch.json:
// Attach; 主に UE4Editor へアタッチして使う { "name": "Attach" , "type": "cppvsdbg" , "request": "attach" , "processId": "${command:pickProcess}" } // Debug; VSCodeからデバッグ用に擬似的なスタンドアローン起動風にデバッグ実行したい場合はこんな感じ "name":"Debug" , "type": "cppvsdbg" , "request": "launch" , "program": "C:/Program Files/Epic Games/UE_4.18/Engine/Binaries/Win64/UE4Editor.exe" , "args": [ "<path-to-uproject>.uproject", "-debug", "-game" ] , "cwd": "${workspaceRoot}" }
こういうのに相当するゴニョゴニョを VSCode でも UE4Editor 側で設定すれば手書きしなくても快適かつ必要に応じて更新してくれるようになった、という話。
手書きする必要が無くなるとロストテクノロジー化するので必要になった時に掘り出すのが面倒になりそうなので備忘録として、あるいはVimやZshを使ってUE4したい人とかの参考にどうぞ。
参考
UE4: 4.18 で Static Mesh のコンテキストメニューから Create Destructible Mesh できなくなっていた件と解決方法
事象
4.17.2 ではコンテントブラウザーで任意の Static Mesh を右クリックして現れるコンテキストメニューにあった Create Destructible Mesh
が 4.18.0 では消えてしまい、代わりに "Remove Vertex Colors" が出現しているように見える。
原因
4.18.0 から Destructible Mesh はプラグインになった。
解決
Apex Destruction プラグインを有効にして UE4Editor を再起動する。
なお、 Remove Vertex Colors
は関係の無い新機能で謎の現象により置き換わったわけではないので Create Destructible Mesh
できるようになってもそれはそれでコンテキストメニューに居る。
おまけ: タイムラインより
気づいた時にはバグかも?って思ったけどプラグイン化しただけだった。 Release Note に書いてくれよ感はある・x・
参考
UE4: 柄の付いた道具の当たり判定
1. 導入
例として「つるはし」の当たり判定を考えてみる。
岩につるはしが当たって効果がある部分は"柄"(一般に木製の棒; stick)ではなく、その先に装着した"頭"(一般に鋼鉄製; head)の部分だけ。便宜上のゲーム表現では柄は当たり判定なし、頭だけ当たり判定ありで、「キャラクターがつるはしを振るうアクション」を行うとそんな当たり判定のつるはしオブジェクトがプレイヤーに合わせて出現するような実装をしたい場合がままあります。
リアリティーを求める場合は柄の当たり判定も実装して力のかかり具合と材質から柄がダメージを受け破壊されてしまう要求もあるかもしれませんが、今回はそこまでせず、古典的なアクションゲームにありがちな便宜上の当たり判定の実装をしたい事にします。
2. 前提となる状態
- つるはしの見た目のメッシュデータ Tsuruhashi を UE4 でインポートできている
- Tsuruhashi をメッシュとして設定した StaticMeshActor の Tsuruhashi_Blueprint を配置できている
例示の簡単のためモデルデータをレベルエディターへドラッグアンドドロップすれば生成される状態で紹介します。 C++ コードで実装する場合、実行中に動的にオブジェクトを生成する場合も本質的には同様です。
3. つるはしの頭の部分にだけ当たり判定を付ける
- Tsuruhashi_Blueprint オブジェクトの RootComponent の StaticMeshComponent に
+Add Component
で Cube を追加する - 追加した Cube の Tsuruhashi_Blueprint オブジェクト内での Location と Scale を適当に設定して当たり判定としたい空間を占めるように設定する
- 追加した Cube のプロパティー Collision の
Generate Overlap Events
が ON になっている事を確認(デフォルトでON)Collision Presets
をOverlapAllDynamics
に設定
- Tsuruhashi_Blueprint オブジェクトの RootComponent の StaticMeshComponent のプロパティー Collision の
Generate Overlap Events
を OFF に設定Collision Presets
をNoCollision
に設定
- Tsuruhashi_Blueprint オブジェクトを
Edit Blueprint
して Event Graph にEvent ActorBeginOverlap
に当たり判定に伴う処理を実装する- note: 動作確認目的では
Event ActorBeginOverlap
のOther Actor
からGet Object Name
してPrint String
すれば十分
- note: 動作確認目的では
- 動作確認が済んだら Cube のプロパティー Rendering の
Visible
を OFF に設定
以上のように当たり判定用に Cube あるいは必要に応じて Sphere や Cone などをコンポーネントとして追加して組み立てると一部分に当たり判定を持つ「つるはし」のような道具の実装は簡単にできる。
4. 応用
- プレイ中の視認によるデバッグ目的や、エンドユーザーへ当たり判定の表示機能を提供したい場合は §3 で追加した Cube の
Visible
を適当なトリガーで ON/OFF できるようにし、マテリアルも当たり判定の可視化用に適当な半透明の黄色ベタなどを設定するとよい。 - 当たり判定の可視化が UE4Editor の開発環境の表示機能だけで十分でメッシュとマテリアルによる表示が不要な場合は StaticMeshComponent の Cube や Sphere ではなく
Box Collision
やSphere Collision
やCapsule Collision
をコンポーネントとして追加するとよい。- note: C++ コードの場合は
UBoxComponent
やUSphereComponent
やUCapsuleComponent
を ctor 等で生成してSetupAttachment
する。
- note: C++ コードの場合は
- アクター単位でなくコンポーネント単位で当たり判定を行いたい場合は Event Graph で
Event ActorBeginOverlap
を定義せずにBind Event to OnComponentBeginOverlap
を定義し、そのTarget
にCube
コンポーネントを与え、Event
へOnComponenBeginOverlap_Cube
などお好みのユーザー定義イベントを束縛させるとよい。- note: C++ コードの場合は
OnComponentBeginOverlap.AddDynamic
で実装する。
- note: C++ コードの場合は
5. 参考
- UShapeComponent | Unreal Engine API Reference
- Unreal Engine | イベント
- Event ActorBeginOverlap | Unreal Engine Blueprint API Reference
- Unreal Engine | 5.オーバーラップしているアクタをテストする
- OnComponentBeginOverlap | Unreal Engine API Reference
- Unreal Engine | 動的デリゲート
- UE4: C++ クラスで実装したアクターのコンポーネントの OnComponentBeginOverlap.AddDynamic 等がうまく動作しない時に確認すること - C++ ときどき ごはん、わりとてぃーぶれいく☆
スマートフォンが落下などにより画面を使用不能に陥った場合の対処方法
Zenfone Go がトイレへ駆け込む際にトイレットペーパーを補充しようとしている間に棚から落ちて画面が死にました。
まあ、操作できません。しかし、幸いな事にこの Android 端末は USB デバッグ機能が ON に設定されています。そこで Vysor を PC の Chrome へインストールし、 USB ケーブルでこの画面の死んだ Zenfone Go を PC に接続します。
接続すると Chrome の Vysor が自動的に Android 側に必要なパッケージのインストールを行い、 PC からポインティングデバイスで操作可能な状態になります。キーボードは International を長押ししてインストールされている Vysor に切り替えると日本語入力含め使用できますが、 Vysor が死ぬことがしばしばありましたので、ポインティングデバイスだけでぽちぽち操作するのが安全なようです。
一部のアプリケーションでは新しいスマートフォンを購入した後にアプリ専用のデータの移行方法が必要などありますから重宝します。
だそく
さて、やはり CAT S60 が欲しいのですが日本では公式な取り扱いがありません。 S40 は安いけど機能、性能的にしょぼいし。 Zenfone のツルツルデザインは滑って落ちやすい事が今回の件以外でもしばしば不便に思っていましたので Zenfone4 など買うかは少々微妙な心境です。