2016/02/29

スカイリムのUIの話

今日はスカイリムのUIについて、制作中につまづいたことや失敗したこと、基本的な作り方の手順についてなど、ささやかですが今まで試行錯誤したことを書きたいと思います。
スカイリムのUIはFlashという有料のソフトで作られているせいか、海外のサイトでも制作に関する情報がほとんどありません。SkyUIのHUDウィジェットみたいにメジャーなものですら、作り方については何の解説もなく、ソースを見て察しろ、みたいな状態です。(私の探し方が下手なだけかもしれませんが)
ゲーム中で使われているUIのFlashファイル自体はかなり昔から出回っていましたが、それをどのように改造したらよいのか、CK wikiのような公式の解説があるわけでもなく、またモーション制作のように有志のチュートリアルのようなものもついぞ見たことがありません。
ン十万もする3Dソフトのモーション作成講座はあるのに、なんでFlashのスカイリムUI作成講座はないんだろうかと思いますが……まあ、Flashなんて四年前から完全に終わってましたからね。
…というか今ではもう、Flashという製品の名称自体が終了してしまいました(合掌)
ところでFallout4も、HUDmenu.swfとかfont_en.swfなんていう馴染みのあるファイル名を見かけるってことは、やっぱりまたUI作成のミドルウェアはScaleformなんでしょうか。
だとしたらFallout4のUI制作もイバラの道になりそうですね。

スタート画面のFlashをセーブ名が見えるように改造してみました。
適当に作ったものですが使ってみたい方がいらっしゃいましたらどうぞ。(startmenu.swf

セーブ名の表示ってFlashのスクリプトで20字以上(表示は17字)が切り捨てられているんです。
何を以って20字なのかは謎ですが……日本語だと全然読めないですよね。

ちなみにフリーソフトで作ったFlashファイルでも、ゲーム画面上に表示すること自体は、アドビの正規品のFlashと同様、問題なくできます。(↓これは「ParaFla」というフリーソフトで作りました)

ただ、このParaFlaというフリーソフトですと、インスタンスのフレームにスクリプトを直付けすることしかできませんので、ゲームのシステムとデータをやりとりするようなUIを作るのは無理っぽいです。
(フリーでもFlashDevelopなら作れそうですが、いまどきAS2.0の環境って構築できるのだろうか…)
でも、MCMメニューの表紙とか、SS撮影用のプリクラの枠とか、表示オンリーのものだったらこれでも充分作れますんで、ご興味のある方はぜひ試してみてください。
Flashのファイルをゲームの画面上に表示させること自体は、意外に簡単です。

ちなみにFlashファイルに画像ファイルを含める場合は「PNG」形式で(JPEGはダメっぽい)、画像は「圧縮しない」という設定にしておかないとスカイリムのゲーム画面上では表示されないです。
正規のAdobe Flashだったら、ライブラリの画像のプロパティの圧縮設定をロスレス(PNG/GIF)にしておく必要があります(最初はこれを知らんかったので、結構悩みました)。
「ParaFla」の画面。PNGファイルの透過の部分もちゃんとキリ抜いた状態で表示されます。

作成したFlashファイルをゲーム上に呼び出すには、SKSEの「UI」スクリプトを使います。
Flashファイルを表示するのに一番簡単な方法は、SKSEの「カスタムメニュー(CustomMenu)」としてFlashファイルをゲーム画面上に呼び出す方法です。
ただし「カスタムメニュー」としてFlashファイルを読み込むと、Flashファイルが表示されている間はゲーム中の動作は一時停止してしまい、操作入力系はFlash上に移ってしまいます。
(本や手紙を開いた時や、ロックピックの開錠中のような感じになります)

【Flashファイルをカスタムメニューとして表示するスクリプトの記述例】
たとえば作成したFlashファイルが「test.swf」という名前で、Dataフォルダ以下の「Interface/exported/obachan」というフォルダに置いてあった場合、そのFlashファイルを表示するスクリプトはこうなります。
UI.OpenCustomMenu("exported/obachan/test", 0)
パスはInterfaceフォルダをルートとして、Flashファイルの位置を指定します(拡張子のswfはいらない)
ちなみに「カスタムメニュー」を閉じる時は、
UI.CloseCustomMenu()
になります。(※カスタムメニューは同時に複数開けないものなので、閉じる時は引数は無いです)
ただし前述した通り、カスタムメニューを開いてる最中はプレイヤーの操作などはできなくなりますので、カスタムメニューを閉じるスクリプトは、プレイヤーの操作やゲームの進行に依存しないものに付けておかないと、カスタムメニューの画面から元のゲーム画面に戻れなくなってしまいます。
もっとも「カスタムメニュー」として使われるようなFlashは、Flashのコンテンツ内に「キャンセル」や「戻る」ボタンなどを用意してメニューから抜けるしくみを付けてあるのが一般的です。
ただ、それはFlash側にスクリプト(ActionScript)を付けないとできないことなので……スクリプト無しのPalaFlaで作ったFlashなどをカスタムメニューとして使う場合は、Papyrusスクリプト側で予めホットキーなどを用意しておいてメニューを閉じるようにするしかないと思います。

ところで私はこの「カスタムメニュー」の、ゲーム中の動作が止まってしまう仕様を、鍛冶や錬金のクラフト中やNPCとのダイアログ中などのように周囲の時間や動作を止めないで表示させる方法はないものかしら、と前々から思っているのですが、どうしたらよいのかさっぱりわかりません。
SkyUIのバージョン5でクラフト系のメニューが追加された際に、ソースをいろいろ見てみたのですが、Flash側の方にはそれらしき記述は見当たらないんですよね。
ゲーム中の動作を止めないで独自のカスタムメニューが作れたら、オブリビオンであったNPCの好感度を上げるミニゲームとか、マイクラみたいな釣りModとか、ゲーム内の動きとUIを連動させた面白いModがいろいろ作れるのになあ、と思うんですけど……私には手の届かない領域のようでとても残念です。


ちなみにゲーム中の進行を止めずにFlashファイルを画面上に表示させたい場合は、現状、私の知る限りでは、HUDメニューのFlashの中に読み込んでHUDの一部として表示させる方法しかありません。
HUDメニューはプレイヤーの状態や対象の情報などを視覚的に知らせるためのUI、いわゆるヘッドアップディスプレイ(HUD)のことですが、スカイリムでは体力やマジカのバーや、コンパス、クロスヘア(照準)のアイコン、クエスト開始の文字エリアなど、様々なパーツを含んだ一つのファイルになっています。
「HUDメニュー」のFlashソースファイル「hudmenu.fla」。
このHUDメニュー内にあるパーツ類は、他のUI画面が表示される時にも、一時的に見えなくなるだけで、ゲーム起動中はずっと画面上に存在し続けているようです。
このHUDメニューの中に自作のFlashファイルを読み込めば、ゲームの操作や進行を止めることなく、HUDの一部として好きな時に表示させられます。
ただしHUDメニュー内では、プレイヤーからの入力を受け付けるものは作れないようです。
試しに文字入力用のテキストフィールドを作って、SKSEの「AllowTextInput」という命令をFlash側につけてキー入力ができるようになるかどうか試してみたんですが、カスタムメニュー内では動くのに、HUDメニュー内ではうまく動きませんでした。
HUDメニュー上でも、カスタムメニューのようにマウスやキーボードの操作系をFlash上に持ってくることができれば、前述したような、「ゲームの動作を止めずにFlash側で操作系のあるメニューを開く」という状態が実現するのですが……私にはどうしたらいいのか、さっぱり見当もつかなくて、お手上げです。


ちなみにこのHUDメニュー上にFlashファイルを読み込む方法なんですが、SkyUIのHUDウィジェットとして表示させるのが一番てっとり早くて簡単です。
SkyUIに頼らずFlashファイルを自力でHUDに組み込むこともできますが、そうする場合は、HUDメニューのムービークリップの中にゲーム上で動的に空のムービークリップを作成して、そこに自分のFlashファイルをロードする、という力技な作業を行うことになります。
拙作の字幕Modなどはその力技なやり方でHUD上に読み込んでいるのですが、読み込む時の深度によってデフォルトのコンパスが消えたり、他のModのFlashのインスタンス名と競合して位置がめちゃくちゃになったり、トラブルが続出して、つくづくUI制作の道は難しいなあと思いました。
ですので、よっぽど特殊なことをしようというのでもない限り、SkyUIの機能を素直に利用してHUDウィジェットとして表示させるのが一番確実です。
改めて書くことでもありませんが、SkyUIはやっぱり偉大なModです。
SkyUIはもともと最初に導入すべきModとして真っ先に名前上がるくらいの神Modですが、UIの参考としてSkyUIのFlashのソースファイルを見るようになって、なおさらその凄さが身に沁みるようになりました。

そういえば…余談ですが、SkyUIのHUDウィジェットは何気にPapyrusスクリプトの配列の128の壁の制限を受けていますんで、ゲーム上では最大128個までしか読み込めない仕様なんですよね。
(SkyUI本体のウィジェットも含めて、です)
128個なんて、そんな大量のMod入れたりしないよ……と思うかもしれませんが、HUDウィジェットはアイコン一個でも一つのウィジェットとしてカウントされてたりするのもあるんで、意外と数を食います。
EFFやFrostfallやDefeatなど、いろんなModで見かける体力バーのようなメーターのウィジェットも、あれも1本のメーターにつき1つのウィジェット、という扱いですからね。
作る側も使う側も気をつけないと、あっさり上限に達してしまうのではないかと思います。
ちなみにMCMの登録Mod数もMAX128まで、っぽいですよね。
こっちの方が気をつけないとヤバイかな?

【FlashファイルをSkyUIのHUDウィジェットとして表示する方法】
さて、FlashファイルをSkyUIのHUDウィジェットとしてゲーム上に表示するのは、Flashファイルさえ用意できれば、ビックリするくらい簡単です。
CKで新規のクエストを一つ作って、それに以下のようなスクリプトを付けるだけ。
scriptname TestWidget extends SKI_WidgetBase

string function GetWidgetSource()
 return "../obachan/test.swf"
endFunction
最低限必要なのは、読み込むFlashファイル名の指定……これだけです。
その他はスクリプトの拡張元の「SKI_WidgetBase」がやってくれてるので、デフォルトの設定のままでよければ、何も追加する必要はありません。
もちろんスクリプトの名称は「TestWidget」じゃなくていいし、読み込むFlashファイルの名前も何でもOKです。SkyUIのHUDウィジェット場合は、ルートの場所が「Interface/exported/widgets」になりますので、「Interface/exported/obachan/test.swf」を読み込みたい場合は、上記のように「../obachan/test.swf」というパスになります。(HUDウィジェットの場合は拡張子が要ります)

ちなみにこのHUDウィジェットのスクリプトは、「SKI_WidgetBase.psc」というスクリプトを拡張したものになりますので、コンパイルの際にはSkyUIのスクリプトのソースファイル群が必要になります。
そういえばSkyUIの最新のv5.1には、何故かスクリプトのソースファイルが付いていませんね。
今まではbsaの中に必ず含まれてたのに……忘れちゃったのかな?
ちなみにv5.0にはちゃんと付属していますので、HUDウィジェットやMCMの機能を使ったModを作りたい方はOLD VERSUINSにある過去バージョンをダウンロードするか、あるいはSkyUIのGitHubから頂戴してくればよいです。


ところでSkyUIのHUDウィジェットとしてFlashファイルを表示するためには、Flashファイルの側でもやっておかなくてはならない設定があります。
最低限必要なのは、Flash内のコンテンツを一つのムービークリップにまとめて「widget」というインスタンス名をつけることです。
ちなみにこのインスタンス名は半角英数の小文字で「widget」です。先頭が大文字(Widget)になっているだけでアウトですので、要注意です。
私はそれでつまづいて何日も悩んだりしました。
FlashのActionScriptはPapyrusスクリプトと違って大文字小文字の区別があるんですよね。
PalaFlaの場合はムービークリップの代わりにスプライトを作って名前をつけます。
画像などのコンテンツはそのスプライトの中に作成します。
これで用意したFlashファイルはSkyUIのHUDウィジェットのローダーによって画面上に表示されるようになるのですが、正直、この状態ではHUDウィジェットと呼べる代物ではありません。
SkyUIのHUDウィジェットの真髄は、単にFlashファイルをHUD上に読み込むだけでなく、そのFlashコンテンツの表示上の操作をあらかじめプロパティや関数として組み込んであって、Papyrusスクリプトだけで簡単に調整できるようにしてくれているところにあります。
画面上のどこに表示するかという位置の設定や、透明度の設定、それにフェードイン・フェードアウトといった演出や、トゥイーン移動までデフォルトで用意されているのだから、驚きです。
その至れり尽くせりの恩恵にあずかるには、Flashのインスタンスに「widget」という名前をつけるだけでなく、そのベースになってるシンボル自体にSkyUIの「WidgetBase」クラスを拡張したスクリプト(ActionScript)をつける必要があります。

しかしながら、このFlashのシンボル(ムービークリップ)にスクリプトをつけるという作業は、フリーソフトのPalaFlaでは行うことができません。
ここから先の作業はどうしてもAdobeのFlashが必要になってしまいます。
ちなみに現在、スカイリムのUIを唯一作成することのできるFlashのバージョンCS6は、体験版としてのダウンロードはできないようでして(試用できるのはシリーズの最新版のみ)、無料の試用期間を利用してためしにUIを作ってみる、ということができません。
なのでFlashでの作り方をいくら詳しく書いても、ぜひお試しくださいとは気軽には言えない現状でとてもせつないのですが……それでもあえて書こうと思います。
Flashのノウハウなんて誰も興味ないかもしれませんけど、このまま頭の中にあるだけでは絶対に忘れてしまいそうだし、それに作り方さえわかれば、アドビ税を払ってでも、いっちょUIを作ってみるか、と思う方がいらっしゃるかもしれないですしね。
FlashはWeb用のコンテンツとしては、皆からばい菌のように嫌われてましたけど、動きのあるビジュアルを作るソフトとしてはかなり使いやすいもので、個人的にはとても完成度の高い、よく出来た制作ツールだと思っています。(もっとも私はActionScript3.0になって挫折したクチでしたが)
扱い方もBlenderなんかよりずっと単純ですし、CKとも似てるところがあります。
まあ、今更Flashなんか習得したところで、何の足しにもならないですけどね……

まずは新規ファイルを作成。スカイリムのUIを作る場合は必ず「ActionScript2.0」を選択します。
ちなみに「ActionScript2.0」はFlashのバージョンCC以降は廃止になりました。

CS6であればMacで作っても全然問題ありません。
Webなどで使われるFlashの場合は、ステージの「幅」や「高さ」や「背景色」などがそのFlashの見かけに関係してきますが、スカイリムのUIではこれらは関係ないので設定は何でも構わないようです。
スカイリムの画面上ではFlash内で作ったコンテンツの大きさがUIのサイズとなります。
ただしスカイリムのUIのFlashは1280×720の画面サイズが基準になっているようでして、ゲーム画面を1920×1080でプレイする時は、1280×720内で作ったものがそのまま1920×1080に拡大されます。
つまり1280×720より大きい画面では、画像は拡大されて汚くなる、ということです。
スカイリムのデフォルトのUIではほとんど画像が使われておらず、ベクターの部品中心で構成されていますが、それはどんな画面サイズでも綺麗に表示させるための配慮かなと思います。

ちなみに1280×720が基準と書きましたが、ゲームをプレイする時の画面のアスペクト比は16:9ではないものもあるわけでして……たとえば800×600とか、画面の横幅が16:9より狭いものについてはどうなるかというと、無理やり4:3の比率に縮小されたりはせずに、途中で画面が千切れます。
つまり1280×720基準ですが、1280×720ギリギリまで中身を作ってしまうと、画面サイズによっては横が見切れてしまうという状態になるわけです。
私は日ごろ、1280×720か1920×1080でしかプレイしていなかったので、横幅の狭い画面で表示させたらどうなるか、ということに思い至らず、1280×720の画面をギリギリいっぱいまで使う大きなメニュー画面を作ってしまうという失敗を冒してしまいました。(SexLab Directorがそれです)
ですので、画面のサイズ自体は1280×720基準で作るのですが、ゲーム中では画面が4:3になることも考慮して、Flash内で作るものの横幅は960pxまでに収めなくてはならないかと思います。

ところで画面のギリギリいっぱいまでUIを表示させたい場合というのもあるわけでして……たとえばマジカのバーやロード画面のレベルのバーなどは、16:9でも4:3でも必ず画面の右端や左端にあって、画面の横幅が狭くなったからといって途中で千切れたりしてませんよね。
それらはどうやって画面にフィットさせているのかというと、Scaleformの機能でゲーム画面の大きさを取得して位置を固定できる関数があって、それを使ってパーツごとに画面の「左上端」「左上中央」「右上端」といった画面上の位置を指定して配置するようです。
※もう少し詳しく書くと「Common/Shared/GlobalFunc.as」でムービークリップ自体に「Lock」という関数が拡張されているので、それを使って各インスタンスの表示位置を固定します。
(たとえばマジカのバーだと「MagickaMeterAnim.Lock("BL");」という記述で、どんな画面サイズでも必ず画面左下のポジションに来るように固定されてます)

ちなみにSkyUIのHUDウィジェットとしてFlashを作る場合は、表示位置に関しては小難しいことを考える必要はありません。前述しましたが、SkyUIのHUDウィジェットはSkyUI側で既に表示位置を調整できる機能をつけてくれてますので、わざわざ自分でそういった機能を作る必要はないのです。
最低限気をつけなくてはならないのは、作るウィジェットの大きさを幅960px、高さ720px内に収めること、だけです。
HUDウィジェットにする場合はムービークリップに必ず「widget」というインスタンス名をつけます。

上記の画像の例では、100×100pxのグリーンの正方形を置いてるだけですが、Flashの中身は自由に何でも作れます。テキストフィールドを置くもよし、画像を使うもよし、ムービークリップの中にムービークリップを散りばめるもよし、アニメーションさせるもよし。
ただし動画やサウンドをライブラリに読み込んで使うことはできません。スカイリムのUI上で音を鳴らしたい場合はまた別途、スクリプトで記述する必要があります。
作ったFlash内のパーツは最後、全部選択状態にして1つのシンボル(ムービークリップ)にまとめます。
前にも書きましたが、SkyUIのHUDウィジェットの場合は、ルートにまとめたムービークリップに「widget」というインスタンス名をつける必要があります。

Flashにあまり馴染みの無い方に向けて補足しますと、「ムービークリップ」というのはスカイリムでいう「Form」のようなものといいますか、Flashにおける標準のベースオブジェクトみたいなもんです。
ちなみにFlashとCKは制作の概念やインターフェースがとてもよく似ているツールでして、ベースになるオブジェクト(Flashでは「シンボル」と呼びます)をステージ上に配置すると、ObjectReferenceのようなインスタンスとして配置される、というしくみになっております。
(つまりインスタンス名は、スカイリムでいう「RefID」みたいなものです)
ただCKのように、オブジェクトウィンドウ(Flashでは「ライブラリ」といいます)からあらかじめ登録されたオブジェクトを選んで配置する、というような方法だけでなく、ステージ上で作ったグラフィックやテキスト、アニメーションなどをグループ化して「ムービークリップ」という何でもありの形態にまとめて、新規のベースのオブジェクト(シンボル)としてライブラリに登録することができます。
そんな所はスカイリム限定の制作ツールであるCKよりもだいぶ自由度が高い、と言えますでしょうか。
ちなみに私はスカイリムをプレイするまでは、Modなんて作ったこともなければ、プログラムの素養もないただのおばちゃんだったのですが、唯一このFlashを触ったことがあったおかげで、CKやPapyrusスクリプトに慣れるのにさほど苦労しませんでした。
ですので、その逆も同様に、CKに親しまれている方ならば、Flashの使い方もすぐに習得できるのではないかと思います。
シンボル(ムービークリップ)のプロパティ画面。
ここでスクリプトをベースのオブジェクトに紐付けます(リンケージといいます)。

ステージ上のコンテンツを選択状態にして「シンボル」に変換すると、上記のようなプロパティの画面が開いて詳細を入力することができます。
(ライブラリにあるムービークリップのシンボルを選んで右クリックし「プロパティ」を選んでもOKです)
「ActionScriptのリンケージ」というのは、CKでベースのオブジェクトのエディット画面を開いて、Papyrusスクリプトを「Add」するのと同じような感覚です。
付けたいスクリプトの名前が「testWidget.as」だったら「クラス」の欄に「testWidget」と入力します。
(「as」というのはActionScriptの拡張子です)
一番上の欄のシンボルの「名前」や「識別子」は適当につけても大丈夫っぽいです。上記の画像ではインスタンス名の「widget」と同じにしちゃってますが、別に何でもかまいません。
一番上の欄の「名前」はBaseIDのようなもの、「識別子」というのは、スクリプトでこのオブジェクトのインスタンスを自動生成する時などに使われます。


ムービークリップにスクリプトを紐づけたら、今度はそのスクリプトファイル自体を用意します。
(上記の画像の例では、「testWidget.as」を用意します)
ActionScriptのソースファイルは、Papyrusスクリプトと同様、単なるテキストファイルですので、お好きなエディタを使って作成・編集できます。
上記の画像の例のように「testWidget」というスクリプトを付けるのだったら、「testWidget.as」というファイルを新規作成して、現在作成中のFlashファイルと同じところ(同じフォルダ内)に保存します。
※スクリプトをフォルダの中に入れて管理したい場合は、リンケージする「クラス」のスクリプト名の前に、そのフォルダ名をドットで繋いで付けます。たとえば「oba」というフォルダの中に「testWidget.as」を入れるのだったら、「クラス」の欄のところは「oba.testWidget」という風に記載します。

SkyUIのHUDウィジェットとして稼動させるために最低限必要なスクリプトは以下の記述です。
import skyui.widgets.WidgetBase;

class testWidget extends WidgetBase
{
 public function testWidget()
 {
  super();
 }
}
見慣れないと最初は「ゲッ」とか思うかもしれませんが、Papyrusスクリプトに慣れている方なら、やってることはさほど変わらないのですぐに理解できるのではないかと思います。
余談ですが、昔、スカイリムのPapyrusスクリプトは「Java」というプログラム言語に似ている、という話をどこかで目にしたことがあります。
でも私はずっとActionScriptに似てるよなー、って思っていました。
でもそれはActionScriptに「Java」と似ている部分があったから、だったのかもしれません。
ちなみに上記のActionScriptをPapyrusスクリプトで書いたら、こんな感じになるかと思います。
scriptname testWidget extends WidgetBase

event OnInit()
 parent.OnInit()
endEvent
上記のスクリプトを見ればわかると思いますが、「testWidget.as」は大したことはしてません。
SkyUIのHUDウィジェットのベースのクラスの「WidgetBase」を拡張して初期化してるだけです。
ActionScriptの方の「public function testWidget()...」のところの記述は、小難しい横文字でいうと「コンストラクタ」といって、このスクリプトが実体化(インスタンス化)した時に最初に行われる初期化の処理になります。
Papyrusスクリプトで言ったら、OnInitイベントのようなものです(たぶん)。
ちなみにPapyrusスクリプトの場合は、拡張元の親と同じことをするだけなら、わざわざ「parent.OnInit()」なんて書く必要はありませんが、ActionScript2.0の場合は自身の初期化の際に「拡張元の親も初期化処理を行いますよ」とちゃんと書いてやらないと自動では行ってくれないようです。
そんなわけで、testWidgetクラスのコンストラクタの中で、「super()」と書いております。
(super()は拡張元の親…スーパークラスのコンストラクタを呼び出す処理です)

スクリプトが完成したら、あとは「パブリッシュ」してFlashファイルを書き出すだけですが、その前にもう一つ、やっておかなければいけないことがあります。
さきほど作成したスクリプトはSkyUIの「WidgetBase.as」を拡張したわけなんですが、Papyrusスクリプトと同様、FlashのActionScriptも他のスクリプトの関数を使ったり拡張したりする場合は、その引用元のスクリプトをちゃんと用意しておかないとコンパイルできないのです。
なので、まずSkyUIのソースファイルをSkyUIのGitHubからダウンロードさせてもらいます。
「src」フォルダ内の「CLIK」「Common」「HUDWidgets」……この3つのフォルダに入っているのがHUDウィジェットをコンパイルするのに必要なスクリプト達です。
今回作成した「testWidget.as」で直接使ったのは、「HUDWidgets」というフォルダの中に入っている「skyui/widgets/WidgetBase.as」だけなんですが、この「WidgetBase.as」の中でさらに「CLIK」や「Common」といったフォルダ配下のスクリプトも使っていますので、この「CLIK」「Common」「HUDWidgets」の3つのフォルダ全部に「クラスパス」を通します。
「ファイル」>「パブリッシュ設定」でFlashファイルを書き出す際の様々な設定が行えます。
「スクリプト」の項目の隣にあるレンチのマークをクリックすると「クラスパス」の設定ができます。
「クラスパス」というのは、Papyrusの例でいったら、インポート用のフォルダの場所指定のことです。
Papyrusスクリプトをコンパイルする時、デフォルトでは「Data/Scripts/source」フォルダに関連するスクリプトのソースファイルを置きますよね。その他にも、Papyrusのコンパイラのオプションを設定すれば別のフォルダにあるスクリプトを参照することができるわけですが、同じようにFlashでもActionScriptをコンパイルする時に参照するフォルダを設定することができます。
「パブリッシュ設定」にある、ActionScript2.0の設定画面で、その参照するフォルダを設定することができますので、「+」アイコンを押して、前述した3つのフォルダの場所を追加します。
ちなみに上記の画像は、各ファイルやフォルダがこんな風↓に置かれている場合の一例です。
指定するパスは作業している環境に合わせて、適宜変更してください。
クラスパスが正しく通っていなかったり、必要なスクリプトが足りていなかったりすると、パブリッシュした時に「コンパイルエラー」のタブにエラーの詳細が出ます。
パブリッシュしてFlashファイル(swfファイル)を書き出した時に何もエラーが出なければ成功です。


さて、長くなって参りましたが、もう一息ですのでめげずにお付き合い下さい。
HUDウィジェットのFlashを作ったら、それをゲーム画面上に呼び出すためのMod(espファイル)を作成しなきゃなりませんが、その作成についても少々補足したいと思います。
ちなみにHUDウィジェットのようなUIを単に表示させるだけのModでしたら、CKでは「Skyrim.esm」などのマスターファイルを最初に読み込む必要はありません。
Skyrim本体のデータは何も参照しませんので。
マスターファイルを何も読み込まないとロードの時間がかかりませんので楽チンです。
まずは前述したように空のクエストを一個作って、そのクエストにFlashファイルをHUDウィジェットとしてゲーム上に読み込むスクリプトをつけます。
scriptname TestWidget extends SKI_WidgetBase

string function GetWidgetSource()
 return "../obachan/testWidget.swf"
endFunction
この最低限のスクリプトで表示させると、こんな風に画面の一番左上端に表示されるかと思います。
これはSkyUIのHUDウィジェットのデフォルトの設定が、ウィジェットの基準点(アンカー)「左上」、ウィジェットの座標「X:0、Y:0」になっているからです。
たとえばゲーム画面の中央にウィジェットを表示させたい場合は、スクリプトにこう追加します。
event OnWidgetInit()
 HAnchor = "center"
 VAnchor = "center"
 X = 640
 Y = 360
endEvent
「OnWidgetInit」というのは、拡張元の「SKI_WidgetBase」で定義されているイベントで、その名の通り、このウィジェットが最初にゲーム画面上にロードされる時に実行されます。
ですので、このウィジェットの初期状態を設定する処理などを書くとよいです。
「X」や「Y」といった値は、ウィジェットの画面上の座標の指定に使うプロパティで、画面の一番左上が「X=0, Y=0」、一番右下が「X=1280, Y=720」になります。
ちなみに画面サイズが「1280×720」ではない場合はどうなるかというと、1280×720基準で配置した時の比率をその画面サイズ上で再現して表示されます。
つまり「X=640、Y=360」という指定だと、画面が1920×1080だろうが800×600だろうが、画面中央に表示され、さらにその半分の「X=320、Y=180」だと、ウィジェットは必ず画面の1/4の位置に、正方形の比率はそのままの状態で配置されるのです。(意味わかりますでしょうか?)
この機能、自分で搭載しようと思ったら、結構ややこしくて面倒な作業だと思います。
本当にSkyUIの作者さまさまです。

「HAnchor」「VAnchor」はウィジェットの基準点……つまり座標を指定する時に、ウィジェットのどの部分をその座標に持ってくるかという、アンカーとなる部分を指定するためのプロパティです。
「HAnchor」は水平方向の基準で、"left"、"center"、"right"の3つです(デフォルトはleft)。
「VAnchor」は垂直方向の基準で、"top"、"center"、"bottom"の3つです(デフォルトはtop)。
つまり画面中央に表示させたい時は、ウィジェットの中心に基準点があった方が指定しやすいので、両方とも「center」にすると良いです。
下の画像のように画面の一番右下にぴったり表示させたい場合は「right」「bottom」が最適ですね。
event OnWidgetInit()
 HAnchor = "right"
 VAnchor = "bottom"
 X = 1280
 Y = 720
endEvent
ちなみにこれらの設定を途中で動的に変えたい場合……たとえばMCMの設定からウィジェットの表示位置などを動かしたい場合は、拡張元のスクリプトの「OnWidgetReset」というイベントを呼び出してやればウィジェットの表示の更新ができます。
Function moveWidget()
  HAnchor = "right"
  VAnchor = "bottom"
  X = 1280
  Y = 720
  parent.OnWidgetReset()
EndFunction
上記の例では「moveWidget()」という関数にしちゃってますが、別に関数にしなくてもかまいません。
ウィジェットを変化させたいタイミングで、関数内の処理をかけばOKです。
ちなみに「parent」というのはスクリプトの拡張元の「SKI_WidgetBase」のことです。
「SKI_WidgetBase.psc」のソースを見れば、他にもどんなイベントやプロパティがあるか一目瞭然ですので、HUDウィジェットを作成する際には一度目を通しておくことをお勧めします。

SkyUIのHUDウィジェットには他にも、フェードイン・フェードアウトさせたり、表示するモードを設定したりする便利機能があるのですが、長くなって参りましたので、割愛します。
ゲーム側からデータを送って、ウィジェットに反映させる方法なども書きたいのですが、いざ説明しようとするととても難しいですね。無駄に長くなってしまうし。途中で飽きてしまう(私が)


ちなみにこれ↓は先日作ったModなんですが、実際に自分でプレイ中に使ってみたら、あんまり使い勝手が良くないことがわかって、つくづくUIってのは難しいなあと思いました。
UIは、ただ作ればいいってもんじゃないですね。
どんなに素晴らしい機能があっても、操作性が悪いと結局、使わなくなっちゃいますから。


昨今のModを見ていると、高性能でいろんな機能があるModほどUIの不自由さがネックになって、使いづらいというか、設定が面倒くさくてわかりづらい、楽しめない、ということが多い気がします。
UIがもっと簡単に自由に作れるといいんですけどねえ……

18 件のコメント:

  1. 動画を見てみたら凄い良さそうなModで驚きました。
    まさかskyrimのゲーム中で日本語入力しているのが見れる日がくるとは……

    返信削除
    返信
    1. クリップボードのテキストをゲーム上に持ってこれる関数を見つけて、これでアイテム名とか日本語で付けられる!と喜んで作ったんですが、予想以上にウィンドウ切り替えてコピペするのが面倒くさくて、結局プレイ中は全然使わなくなってしまいました。
      毎回毎回ウィンドウ切り替えてエディタ開かなくても済むようにコピペした単語をいくつかストックできる機能とか、もうちょい使い勝手を良くする工夫をしないと実用にならなそうです。

      削除
  2. MOD製作万年初心者の自分には夏頃にここが無くなってしまうのがとても残念です。
    今回も勉強させていただきありがとうございました。

    返信削除
    返信
    1. こちらこそ見てくださって有難うございます。
      ぼんやりしてるとすぐ夏になっちゃいそうですね。更新頑張らないと……

      削除
  3. 画像圧縮してたらダメだったのですね……ずっと分からなくて、もう諦めてました。あふん……

    SkyrimのUI制作情報はホント見当たらず、日本語だとたぶんここが唯一なので、とても有り難いです。
    「UIを作るためだけにオワコンのFlash(しかもクソ高い)を購入しても良い!」という人は多分居ないので、そのあたりが原因なのかな~と思います。
    Adobe正規品が無くても、ParaFlaでガワだけ作ってFlashDevelopでスクリプトを埋め込む方法で作れないことは無いのですが、SkyUIなどの.flaで配布されてるリソースを使えないので正直とても面倒くさいです。

    >周囲の時間や動作を止めないで表示させる方法
    Flash側では無理なので、skse teamにお願いして対応してもらうか、自分でskseプラグインを書いて対応するしか無いです。

    あとは
    ・拡大縮小の方法を指定(全体が表示されるサイズにする・アスペクト比を無視して画面にぴっちり合わせる・拡縮しない)
    ・メニューの表示深度(HUDMenuよりも下にしたいとか)
    ・メニュー表示中の入力コンテキスト変更
    ・メニュー表示中のセーブ・ロード有効・無効化
    ・マウスカーソルの有効・無効化
    このあたりもFlash側では無理なので、skse teamに土下座する必要があります。

    返信削除
    返信
    1. > 周囲の時間や動作を止めないで表示させる方法

      ああ、やっぱりSKSEの領域だったのですね。
      「CustomMenu.cpp」の26行目あたりに出てくる「kType_PauseGame」とか
      単語的にものすごくアヤしい、とか思ってたんですよねえ……

      やっぱりSKSEのプラグインを作れるようにならないとダメですね。
      SKSEの更新履歴とか見ると、ある意味、SKSEの歴史はScaleform拡張の歴史、と思えるくらい、
      初期の頃からUI関係の機能拡張に取り組んでるのがうかがえて、
      UIをどうにかしたいなら、SKSEを攻略する必要があるんだろうな…と薄々感じてました。


      ひみかさんって「Lock-On」を作ってらっしゃった方ですよね?
      ソースが公開されているのを見つけて、有難く拝見させていただいてます。
      あれを参考に、シムズみたいにNPCの考えてることを吹き出しのアイコンで表示するようなModが作れたらいいなーと思っているのですが、まだまだ私は参考にできるレベルにも達していなくて、道のりは長いです。

      削除
    2. そうなんです、Lock-Onの照準をPNGで好きな画像に差し替えられるようにしたかったのですよね。
      「照準が虹色でゲイっぽい、なんかすごい」っていうコメントをいっぱい頂戴していたので……

      シムズみたいな吹き出しアイコンは
      https://twitter.com/himika/status/693827749689995265
      前に、こういうのを作ったんですが、これを魔改造すれば行けそうでしょうか。
      もし使えそうなら、少しブラッシュアップしてから、どっかにソースごと投下してみます。

      削除
    3. わあ、凄い!!……こういうこともできるんですね。
      この動画みたいに、NPCの頭上にHUD上のコンテンツを追従させるのってどうやるんだろうと前々からずっと不思議に思っていたんです。
      クエストマーカーがNPCやアイテムの頭の上に出るしくみが、Flash側で実装されてたら良かったんですが。

      ところでこんなところでお尋ねするようなことではないんですけれども、「Lock-On」のソースをdllにコンパイルするのって「libSKSE」が必要ですよね?
      これって現在公開されている「libSKSE」でもビルド可能でしょうか?
      なにぶん先日ツールをインストールしたばかりの初心者なので見当違いのことをやってるのかもしれませんが、思いつく限りのことを試してもうまくいかなくて……
      (ちなみにVisual Studio 2013を使っております)

      削除
    4. 最新のlibSKSEはVisual Studio 2015で書いているので、そのままだとコンパイル通らないかもしれません。ちょっと確認してみます。

      それとGithubで公開してるLock-On、実はこれ最新のソースじゃなくて、2つ前ぐらいのバージョンです。申し訳ない。。。
      (去年HDDが壊れてしまって、作りかけのMODが全部飛んでしまいました・・・)

      削除
    5. ああ、Visual Studio 2015でしたか……だからPlatformToolsetがv140_xpになっていたのですね。
      libSKSE.slnを覗いたらVisual Studio 2013という表記があったので2013を使っていたんですが、中のskseやcommonの設定がv140_xpになっていてビルドできないので、無理くりv120に変えてました。

      Visual Studio 2015にして、下記のような調整をしたら「Lookon.dll」が無事にコンパイルできました!

      「Event.cpp」内の以下の名称を変更
      「sourceID」→「sourceFormID」
      「projectileID」→「projectileFormID」

      インクルードディレクトリに以下を追加
      $(WindowsSdkDir)include\shared
      $(WindowsSdkDir)include\um
      $(UniversalCRT_IncludePath)
      $(Home)\include\libSKSE

      ライブラリディレクトリに以下を追加
      $(WindowsSdkDir)lib\winv6.3\um\x86
      $(UniversalCRT_IncludePath)
      $(UniversalCRT_LibraryPath_x86)
      $(UniversalCRT_LibrarvPath_arm)
      $(UniversalCRT_LibrarvPath_x64)
      $(Home)\lib\libSKSE
      ※libSKSEをビルドしてもなぜか「lib」フォルダが出来なかったんですが、自前で作って「skse.lib」と「skse_common.lib」を入れました。


      ああ、嬉しい……これでいろいろ試しながら、SKSEのプラグインの作り方について知ることができます。
      「Look-on」はSKSEだけでなくFlashのソースファイルまで付いていて、とても有難いです。
      ソースを公開してくださって、本当にどうも有難うございます。

      削除
  4. いやいやいや...RenameTool名前を変更するModは既に実用レベルじゃないですか!!
    凄い便利そうなんですがw

    返信削除
  5. 今年の夏頃、記事消えるですよね?
    面倒だとは思うのですがいっそうの事、全記事バックアップ取って他の処に
    移るとかはやらないでしょうか・・・

    SkyUIに手加えて日本語入力まで出来るとか凄い事なんですが

    返信削除
  6. いつも楽しく拝見しております!
    私も上記の方々↑に賛同です。多少手間かかってもこれ使いたい・・・。うちも西尾にしたい。
    それからこのサイトは大好きだったので、どこかにバックアップを取っておいて下されば嬉しいです。技術的な話ももちろん勉強になりますが、検証記事や巡礼のお話はスカイリムの世界観が広がって、楽しみを倍増してくれていたので・・・。

    返信削除
  7. コメントどうも有難うございます。

    日本語入力といってもゲーム内で入力できているわけではなくて、単にクリップボードのテキストをコピペするSKSEの関数を使ったというだけなので全然凄くないんですが……
    「西尾にしたい」というお言葉で、ちょっとヤル気が出て参りました(笑)
    使いやすいようにもう少し何とかして、公開できるように頑張ってみますね。

    ああ、それにしてもやりたいことが多すぎて時間が足りない……
    一日がせめてあと4時間、長かったらいいのに。


    ちなみにこのブログは、記事やブログ自体が無くなるわけではないんですよ。
    画像などのリンク先がなくなるだけで、テキスト自体は消えないんです。
    (まあ、テキストだけ公開してても見苦しいので、それですべての記事を休止状態にしようと思ってるんですが)

    画像をどこかに置き直してリンクを再設定すれば今まで通り表示できるので、いくつかの記事は閲覧できるように復元するつもりです。
    まあ、全記事を一気に復元する、というのは、はちょっと無理ですが。

    返信削除
  8. 名前変更の動画を見ながら、口から無意識に「すげー、いやこれすごいわ」などといったような言葉がこぼれだしておりました、感動しました!

    返信削除
  9. ↑↑↑の、会話の吹き出しを表示するMODとソース、投下しておきますね。
    本当は先週の土日に投下したかったのですが、時間がとれなくて遅れてしまいました。すみません。
    http://blog.himika.com/2016/03/floating-menu-and-ballon-widget.html

    これを魔改造すれば、skseプラグインを自作しなくても、アクターに追随するウィジェットを自作できると思います。
    (とりあえず必要そうな機能は全部dllにブチこんでおきました)

    返信削除
    返信
    1. プラグインを作らなくてもいいように、何から何まで用意してくださって、本当にどうも有難うございます!
      早速試してみたんですが、いい感じに思い描いていた通りの吹き出しが作れて、もう嬉しくって一人でニヤついております。
      UIを弄るのって、わからないことだらけで大変ですが、やっぱり面白いですね。


      セリフのTopicのテキストや開始・終了時が拾えるイベントも凄く遣いでがありそうですね。
      日本語と英語の字幕を同時に表示させたりとか、吹き出しに関係なく、便利で面白いmodが作れそうです。

      削除
    2. 私もこのサイトの解説にとても助けられた一人なので、もしお役に立てたのでしたら嬉しいです。

      完全に忘れてたのですが、Fash側キー入力を受け取れるようにしておきますね。
      あとは、FlashからPapyrus関数を直接呼び出せると色々と捗りそうなので、そのあたりも暇をみて足してみます。

      削除