UMG用にテクスチャアトラスマテリアルを作る
※ UE4.13から、Paper2DスプライトがUMGで使えるようになりましたので、このマテリアルは必要なくなりました
上の記事の続きです。
前回は急ぎであまり検討できなかったので固定サイズからの切り出しまででしたが、ようやく任意サイズの切り出しができるようになりました。
以下の画像の通りです。なお、TextureSourceは指定しているテクスチャの全体像です。
切り出したい範囲(画像上部:SpriteRect)とテクスチャサイズ(画像下部:TextureWidth/TextureHeight)を指定すれば、その範囲が表示されます。UV値ではなくピクセルサイズで指定します。
SpriteRectはVector4Parameterにしています。RGにRectの左上位置、BAにRectのサイズ(幅・高さ)を入れます。
行っている計算は、描画したいサイズがUVとして(0.0,0.0)~(1.0,1.0)になるように拡大してから、描画原点をズラします。最後にUV値になるようにテクスチャサイズで割っています。
プレビューは正方形ポリゴンなので縦横比が崩れていますが問題ありません。
マテリアルをUMGのImageWidgetに設定して、ImageWidgetのサイズを設定し「SizeToContent」にチェックを入れれば、ドットバイドットで表示されます。
あとは、マテリアルインスタンスにして、UMGで使う画像の数だけインスタンスを用意して使います。
UnrealEngine4で2Dゲームを作ろう! 「2Dゲームを作るために必要なこと 機能編」
「UnrealEngine4で2Dゲームを作ろう!」の最終回。
2Dゲームにするための設定などを紹介した「基本編」の続きです。
UE4の幾多の機能が2Dゲームだと使えるのか使えないのかを紹介します。すべて検証しているわけではありませんので、自分が使った範囲での紹介となります。
個々の機能の詳細については、ドキュメントを参照してください。
目次
移動(Movement)
問題なく使えます。
移動させるには、大きく2つの方法があります。自前で座標計算する方法と、MovementComponentを使う方法です。
レトロ目な2Dゲーム作るのであれば自前で座標計算するしかありませんが、そうでない時はMovementComponentを使うことができます。
MovementComponentを使った方法は、加速度がどうしてもついてしまうため、加速度なしの移動が欲しい時は自前で座標計算します。
自前で座標計算する
ActorのLocationを計算するノードはすべて使えますので、AddActorWorldOffsetなどを使ってActorを動かします。
Sweep引数にチェックを入れることで、Collisionのヒット処理が動くようになります。
Teleport引数は物理挙動に影響するらしいですが、自分は物理機能は使っていませんのでよくわかりません。
MovementComponentを使う
MovementComponentとは、名前の通り移動を担うコンポーネントのことです。いくつか種類がありますが、2Dゲームで主に使うのは、FloatingPawnMovement(以下FloatingPawn)とProjectileMovement(以下Projectile)の2つになります。
FloatingPawn
名前の通り、浮いているポーン用のMoveCompです。一番コンパクトに実装されているMoveCompで、2Dゲームには必要十分な機能を持っています。
FloatingPawnは座標を与えて移動するのではなく、速度のようなベクトルを与えることで移動を行います。
※解説書きました
katze.hatenablog.jp
Projectile
Projectile(投射)の名前の通り、弾などの投射物の移動計算を行います。バウンドさせることもできるので、跳弾させることも簡単にできます。
2Dの場合、弾もFloatingPawnで問題ないといえばないのですが、Projectileは誘導機能があるので、誘導弾を作る時はProjectileを使うことができます。
ただ、実は誘導計算がいまいちで、移動し続けるActorに対して誘導する際に、一度外れてしまうと弾の軌道がなかなか目標に近づいていきません。そのため、誘導をONにした弾は一定時間で消えるように設定しておくのをお勧めします。
その他
3Dゲーム(FPS/TPS)のキャラクター用にCharacterMovementComponentというのもありますが2Dゲームにはオーバースペックだと思います。
また、MovementComponentは、対応するActorの座標のフレーム間差分も考慮した速度を発生させるので、SetActorLocationなど直接座標を変更するノード併用する時は注意が必要となります。
衝突(Hit/Collision)
問題なく使うことが出来ます。
2D専用の仕組みは準備中ということなので、3D用の仕組みをそのまま流用して使います。Collisionや物理による移動方向をゲームとして使っている平面に制限しておくと良いと思います。
ただ、移動しているブロックするCollision同士がぶつかった場合、片方のCollisionがもう片方のCollisionに乗り上げてしまうことがある挙動を確認しています。移動方向を制限していても発生します。乗り上げてしまうと、高さ方向が合わなくなるので、次からブロックしなくなってしまいます。
ちゃんとした解決策はまだ見つけられていないのですが、ブロックを検出した際に乗り上げたかをチェックして元に戻す処理がいるかもしれません。
ナビゲーション(NavMesh)
問題なく使えます。
NavMeshに従って移動を行うMoveTo系ノードは、FloatingPawn(もしくはCharacterMovementComponent)を要求しますので、NavMeshで動作させるPawnには、それらを追加しておく必要があります。
Particle
問題なく使えます。
パーティクルの向きを速度に合わせて回転させるPSA_Velocity設定が、正射影カメラだと正しく動かないバグがあります。
AnswerHubではUE4.9で修正したとありますが、実際にはまだ修正されていません。
BehaviorTree
問題なく使えます。
Paper2D用のTaskなどは用意されていませんので、DecoratorやTaskはすべて自作する必要があります。
Audio
問題なく使えます。
2Dだと距離減衰などをさせると逆に違和感が生まれることもありますので、切ってしまって良いと思います。
Physics
2D用のPhysicsは準備中ですので、3DのPhysicsを流用することになりますが、使うことはできます。
まだちゃんとPhysicsを使っていませんので、どんな罠があるかはわかりません。
UnrealEngine4で2Dゲームを作ろう! 「2Dゲームを作るために必要なこと 基本編」
2Dゲームとは直接関係のない話題ばかりになっているので、いったん2Dについて一通りまとめて、「UnrealEngine4で2Dゲームを作ろう!」シリーズはいったん締めたいと思います。
UE4に関する話題の更新は、まだネタもあるので続けますのでご安心(?)を。
ドットバイドット表示設定やスプライトについて紹介する「基本編」と、2DゲームにおけるUE4の機能について紹介する「機能編」の2本立てでお送りします。
対象バージョンは、UE4.10以上(Windows)です。
ドットバイドットで表示する
ドットバイドット表示とは、ディスプレイの1ピクセルとゲームの1ピクセルのサイズをぴったり合わせた表示のことです。ドットバイドット表示にしないと、スプライトがボケたりズレたりします。スプライトのボケズレはポリゴンよりかなり目立つため、できれば避けたい所です。
UE4のドットバイドット表示は、ウィンドウ・カメラ・PixelPerUnitの設定を適切に行うことで実現できます。
ウィンドウの設定
ウインドウの設定(UE4.11以降)
UE4.11で、ウインドウサイズやフルスクリーン設定がBPノードとして公開されました。
GameUserSettingsを取得して、SetScreenResolution/SetFullscreenModeで設定し、最後にApplySettingsを読んで設定を適用します。
ウィンドウサイズ設定(UE4.10以前)
ウィンドウサイズ設定の仕方は、いくつかありますがコンソールコマンドを使う方法をお勧めします。
ExecuteConsoleCommandノードを使い「r.SetRes 幅x高さ」とコマンドを入れます。幅x高さの後にwだと「ウィンドウモード」、fだと「フルスクリーンモード」になります。
このコマンドを最初にロードされるLevelやGameModeのBeginPlayで呼ぶことで、ゲーム起動時にウィンドウサイズが設定されます。
フルスクリーンへの対応(UE4.10以前)
ドキュメントにちゃんと書かれていないのですが、UE4は2種類のフルスクリーンをサポートしています。
1つはディスプレイサイズも設定したウィンドウサイズに変更するフルスクリーン(以下単にフルスクリーン)、1つはウィンドウサイズを現在のディスプレイサイズに拡大するウィンドウフルスクリーン*1、です。
これらの切り替えは、ウィンドウサイズの設定と同じようにコンソールコマンドで切り替えを行います。
「r.FullScreenMode 0」ならフルスクリーン、「r.FullScreenMode 1」ならウィンドウフルスクリーンとなります*2。
このコマンドは「r.SetRes」コマンドの前に呼ぶ必要があります。
フルスクリーンとウィンドウフルスクリーンの主な違いは以下の通りです。
フルスクリーン | ウィンドウフルスクリーン | |
---|---|---|
アスペクト比 | ディスプレイのアスペクト比になる | カメラの設定に従う |
DPIスケーリング | ウィンドウサイズが使われる | ディスプレイサイズが使われる |
特にDPIスケーリングの違いは忘れがちなので、ちゃんとDPIスケーリングのカーブを設定しておきましょう。
ウインドウリサイズへの対応(4.14以降)
常にドットバイドットで表示するために、ウィンドウの最大化やマウスドラッグによるウィンドウサイズ変更をできないようにします。
[ProjectSettings] → [Description] → [Settings]にて、最大化・リサイズなどの有効無効が設定できるようになりました。
ウィンドウリサイズへの対応(4.13以前)
UE4.13以前で、実現するにはC++を利用する必要があります。
BPから呼び出すのことのできるC++関数を定義します。関数の中身は以下の通りです。
#include <windows.h> void UCommonBPFunctionLibrary::SetupSpriteGameWindow() { // Editor起動の時は何もしない if(GIsEditor) return; // MainWindowのウインドウハンドルを取得する HWND hWnd = NULL; TSharedPtr<SWindow> MainWindow = GEngine->GameViewport->GetWindow(); if(MainWindow.IsValid() && MainWindow->GetNativeWindow().IsValid()) { hWnd = static_cast<HWND>(MainWindow->GetNativeWindow()->GetOSWindowHandle()); } if(hWnd) { LONG Style = ::GetWindowLong(hWnd, GWL_STYLE); // ドラッグによるサイズ変更と、最大化ボタンを無効にする Style &= ~(WS_THICKFRAME|WS_MAXIMIZEBOX); ::SetWindowLong(hWnd, GWL_STYLE, Style); ::ShowWindow(hWnd, SW_SHOW); } }
ビルド設定に、Slate/SlateCoreモジュールを追加してください。
この関数をウィンドウモードに変更した際に呼び出すことで、ウィンドウリサイズを無効にすることができます。
C++の関数をBPに公開する方法は、「UE4 C++コードをブループリントで使えるようにする(関数ライブラリー編) - Let's Enjoy Unreal Engine」あたりを参照してください。
カメラの設定
カメラで重要な設定は、図の緑線を引いた4つの項目です。
項目 | 意味 | 設定値 |
---|---|---|
ProjectionMode | 射影モードを設定する | Orthographic(正射影) |
OrthWidth | 正射影の時のカメラの範囲とする幅(UEUnit単位) | 画面幅のピクセル数を入れる。図だと幅1280ピクセル |
ConstrainAscpectRatio | アスペクト比を維持するかどうか | チェックを入れる |
AspectRation | アスペクト比 | 画面幅÷画面高さ の値を入れる。直接計算式を入れて良い |
PixelPerUnitの設定
最後にPiexlPerUnit(以下PPU)の設定を行います。PPUとは、名前の通り、1ユニット単位のピクセル数を設定する項目です。
使うスプライトシステムごとに設定する必要がありますが、とりあえず、1.0を入れておくのが一番簡単です。
1.0にすれば1ユニットが1ピクセルになりますので、座標の値がピクセルと一致します。様々な計算が楽になります。
もし、1.0以外の値を使う時は、カメラのOrthWidthの値も忘れずに変更してください。OrthWidthの正確な算出式は、「画面幅(ピクセル)×PPU」です。
本記事で紹介する2つのスプライトシステムでのPPU設定場所は次の通りです。
Paper2D
[プロジェクト設定]→[エディタ]→[Paper2D Import]→[Default Piexel Per Unreal Unit]
スプライトを作る時のデフォルト値として設定しておくのが簡単です。
スプライトごと、個別に設定したい場合は、設定したいPaper2D Spriteを開いて、[Sprite]→[Pixel Per Unit]で設定できます。
SpriteStudio
[SsPlayerComponent]→[Sprite Studio Render Settings]→[UUPer Pixel]
こちらは、1ピクセルが何ユニットかという設定なので、Paper2Dとは逆値を設定する必要がありますので、両方使う場合はご注意ください。
2Dの描画(Sprite)
UE4で、2D(スプライト)描画を行うには、現状2つのシステムがあります。
UE4が公式に用意しているPaper2Dシステムと、WebTechnology社が制作ししてるSpriteStudioシステムです。
正直な所、どちらも一長一短です。共存は問題なくできますので用途に合わせて使い分けます。
Paper2D
まずは公式の方から、細かい使い方はドキュメントを見ていただくとして、ここでは概要を紹介します。
Paper2Dの機能は大きく2つあります。Paper2D Sprite と Paper2D Flipbook です。
Paper2D Sprite
名前の通りSpriteを描画する基本機能です。Paper2DのシステムはまずテクスチャからSpriteを作ってから操作を行います。
1枚のSpriteを任意の設定で描画します。
Paper2D Flipbook
任意枚数のPaper2D Spriteを指定した時間で連続再生する機能です。いわゆるパラパラアニメを実現する機能です。
長所
UE4公式なので、UE4の機能との親和性が高いです。マテリアルも任意に設定できますし、ダイナミックマテリアルインスタンスも使えます。
最近、新機能の追加が行われていませんが、これからの機能追加も期待できます。
短所
間接アニメを簡単に作ることはできません。間接アニメとは、2D絵を腕・胴・脚といった部分に分解して、個別に動かすことでアニメーションさせる手法です。Flipbookはレイヤーに対応していませんし、キーフレームには1つのSpriteしか設定できませんので、単純なパラパラアニメしか作ることができません。
その他
他にも、マップチップを使用して任意サイズのスプライトを作るTileMap機能もあります。
SpriteStudio
もう一つはSpriteStudioです。2Dアニメ制作ツールですが、パラパラアニメを作るのはもちろんのこと、特に関節アニメ制作に力が入っているツールです。
インディーライセンスならばすべて無料で使うことができます。Webサイトを見ると半年だけとありますが、半年ごとにライセンスを取り直して良いという公式の見解があります。
@A_Lakryu__m 半年ごとの更新、になります。更新のタイミングで利用条件満たしてれば、そのまま再申請できますよー。
— OPTPiX SpriteStudio (@spritestudio) October 1, 2014
SpriteStudioそのものは、2Dアニメを制作するためのエディタです。エディタで作ったデータを読み込んでUE4上で使うにはSpriteStudioプラグインを使います。
SpriteStudioプラグインは完全に無料だそうです。プラグイン開発はWebTechnology社の認可を受けて、あのhistoria社が行っていますのでプラグインの出来も問題ありません。
エディタの使い方、プラグインの使い方は、各公式サイトのドキュメントを参照してください。
長所
- 間接アニメを作ることができます。
- 元からゲーム用途を想定して作られているため、なかなかかゆい所に手が届く出来です。アニメーションエディタとしても優秀ですし、PGとしてはアニメーションにデータを埋め込んで、それをイベント(OnSsUserData)として簡単に取れるので連携がしやすいです。
Spriteシステムの使いわけ
基本的にはSpriteStudioを使うようにして、カスタムマテリアルが必要ならばPaper2Dを使うのが良いと思います。
描画順
スプライトの描画順は、カメラに対する距離を調整することで行います。
見下ろし(XY平面)ならZ値、横スクロール(XZ平面)ならY値を調整することで、描画順をコントロールします。
見下ろしの場合は、スプライトのpivotをベースライン(Spriteの一番下のライン)に設定することで違和感の少ない描画順を設定することができます。
描画順を設定するのは、Spriteだけにするのをお勧めします。Actorごと動かしてしまうとCollisionも動きますので、調整が大変になります。
SpriteActor(Pawn)
最小の機能を持ったSpriteActor(Pawn)は、空のActor(Pawn)にCollisionComponent/Sprite系Componentを追加して実装します。
図では、FlipbookとSsPlayer(SpriteStdioのComponent)を両方いれてますが、実際には必要な方だけいれてください。
Sprite系Componentは、必ずCollisionComponentの子供にします。そうしないとCollsionヒットした際のブロック処理が上手く動きません。
もしCollisionComponentを使わずに、Spriteに設定したコリジョンを使う時は、Sprite系Componentをルートに配置します。
もちろん、他に必要なComponetがあれば追加します。おそらく移動系とサウンド系は追加することになると思います。
フレームレート(FPS)の設定
UE4は可変フレームレートで実装するのが基本になります。そのため、Paper2DもSpriteStudioも可変フレームレートで動作するようになっていますので、UE4の機能を使って実装している限りは特に気にする必要はありません。2Dアニメーションは、3Dのモーションのような補間はされませんので、極端にフレームレートが落ちた場合はアニメーションのフレームが飛んでカクカクすることはあります。
とはいえ、FPSをコントロールしたいと思うこともあると思いますので、その方法を紹介します。
*1:仮想フルスクリーンとも呼ばれます
*2:ちなみに、この引数はEWindowMode列挙型に連動しています
*3:'Use Fixed Frame Rate' not working properly - UE4 AnswerHub
*4:実時間経過は無視して、1フレごとに設定された時間が経過したことに強制的にする
UnrealEngine4で2Dゲームを作ろう! その17 UMGでテクスチャアトラスを使う
※ 任意サイズに切り出すマテリアルが作れましたので、以下の記事も参照してみてください
katze.hatenablog.jp
UMGにおいて画像を使いUIを作るにはimageウィジェットを使います。
imageウィジェットは、グラフィックを表示するのにSlateBrushを利用していますので、Brushを設定することで画像を表示します。
Brushのimage設定には、テクスチャもしくはマテリアルを割り当てることができます。
テクスチャ指定がお手軽ではあるのですが、テクスチャ全体が表示されてしまいます。
テクスチャ指定で作るには、imageウィジェット1つに付き1つのテクスチャを用意すれば良いのですが、最近の描画システムはテクスチャ切り替えのコストが重いので、できれば避けたい所です。
しかし、困ったことにimageウィジェットはテクスチャアトラスに対応していないため、テクスチャから部分的に画像を切り出すのは自前でやる必要があります。
幸いBrushはマテリアルを使うことができますので、テクスチャから必要な部分を切り出すマテリアルを画像ごとに作ります。
マテリアルインスタンスも利用してシェーダー切り替えコストも抑えたい所ですが、どう汎用化するかはお任せしまして*1、ここでは簡単な例と考え方を紹介します。
テクスチャを切り出すマテリアル
一番簡単な例として、切り出す画像が等間隔で並んでいる場合を考えます。
先ほどの横2列 縦4列並んでる画像から、ひとつ切り出してみます。
マテリアルは以下の通りです。
最初のADDで画像内の分割された位置(横,縦)を指定します。次のDivideで横を2分の1、縦を4分の1にして1枚分に切り出します。
マテリアルの仕組み
imageウィジェットは、1つの四角ポリゴンを使ってBrush設定に従って描画されます。その四角ポリゴンに割り当てられるUVは、左上(0,0)~右下(1,1)となっているようです。
そこで、欲しい画像の範囲がUV(0,0)~(1,1)になるように演算をいれます。
ADDによってUVの原点をズラし、そこから分割数で割ることで1つに切り出します。
ADDする値はDivideされることを考慮にいれます。Divideしなければ、横に1画像ズラすには0.5足しますが、横は2分の1されますので、2倍して1を足すことで1画像分ズレることになります。縦も同様です。
Misc
パタパタアニメを仕込むのは、FlipBookマテリアル関数を使えばできるようです。
テクスチャアトラス対応の要望自体は上がっているみたいですので、対応を期待したい所です。
*1:描画系苦手なので他力本願! むしろ、良い感じのマテリアルが出来たらご教授願います……
UnrealEngine4で2Dゲームを作ろう! その16 CreateEventノード!
イベントディスパッチャーってやつがあります。
イベントディスパッチャーにイベントをBindするノードの仕様で、イベントを必ず同じEventGraph上に作らなければならず、イベントディスパッチャーを使い始めるとなかなかスパゲティなコードになってしまい困っていました。
関数をEvent化してbindできるようになってくれればなぁ、と思い調べた所、できるようになっていました。それがCreateEventノードです。
リリースノートを見るとUE4.9で「使いやすくしました」とあるので、前々からあったようです。
New:CreateEvent nodes are now more user friendly - they will use the current blueprint as the default context and no longer suggest that the user select an asset for context.
使い方
例えば、以下のようなイベントディスパチャーがあったとします。
integer1つと、Stringを1つ引数に取るイベントとします。
bindするイベントとまったく同じ引数を持った関数を定義する
ブループリントクラス内で関数を定義します。引数は、イベントディスパッチャーのものと同じにします。
引数の名前は、わかりやすく同じにしていますが同じである必要はありません。引数の型・数・順番があっていればOKです。
bindノードをおいて、CreateEventとつなぐ
bindノードにつなぐと、CreateEventノードの下部に「関数を選択」と出ます。
関数を選択から先ほど定義した「StateEnd」を選ぶ
これで、bind完了です。
関数リストにbindしようとした関数が出て来ない場合は、引数が間違っているということになりますので見直して見ましょう。