インターフェース
※2025/10/6、英wikiよりkagi翻訳を通しました。機械翻訳なので一部不自然な日本語があるかもしれません。ぜひ編集してくれるとありがたいです。
CK3のユーザーインターフェース(UI)は高度に改造可能ですが、そのためUI Modはチェックサムを変更します。これはマルチプレイでのチートや非同期化を防ぐためです。
パッチ1.9以降、UI Modを導入しても実績は無効化されません。
ゲームにはGUIエディタが含まれていますが、機能が不足しています。
Modderができること:
- インターフェースの見た目のスタイルを変更する*
- ウィンドウを移動・リサイズ可能にする
- 要素を変更・削除する
- 新しいボタンを追加する
- コードからより多くの情報を表示する
- 新しいウィンドウを追加する
Modderができないこと:
- *新しいHUDスキンの作成。ゲームはMod内の新規.skinファイルを無視します
- 新しいホットキーの追加。既存のものの再利用のみ可能で、.shortcutsファイルがMod内にある場合、ゲームはそれを無視します
- 開発者が対応を入れていない限り、あるウィンドウの情報を別のウィンドウに表示すること
基本[編集 | ソースを編集]
CK3のインターフェースはgame/guiフォルダ内の.guiファイルで作られており、htmlファイルにやや似ています。
そのため、VS Code、Sublime、Pulsarなど任意のテキストエディタで編集できます。シンタックスハイライトはPythonかPerl 6を選ぶと相性が良いです。
CK3はテクスチャに.ddsファイルを使用し、game/gfx/フォルダに保存されています。多くの箇所では.pngファイルも受け付けます。
.ddsファイルの編集・保存には、Photoshop+Intelプラグイン、またはGIMP+このプラグインを使ってください。
起動オプション
ゲーム内でguiファイルを自動リロードし、コンソールコマンドを使うには、起動オプションに-debug_mode -develop
を追加します:
- Steamでゲームを右クリックし、プロパティを選択。下部の起動オプションに
-debug_mode -develop
を入力
.guiファイルを保存するたびに、ゲーム側でリロードされます。
重要なコンソールコマンド:
dump_data_types
- 利用可能なすべてのGUI関数を、ログフォルダ(Documents/Paradox Interactive/Crusader Kings III/logs/data_types)のdata_types*.logに一覧出力します
検索しやすくするため、すべてのログを結合できます。
手早く行うには、そのdata_typesフォルダに以下のコードの.batファイルを作成して実行します: type *.txt > ALL_DATA_TYPES.txt
tweak gui.debug
- UI要素のハイライトを有効にします。全オプションのチェックを外し、gui.debugにチェックを入れます。ツールチップに当該要素の正確なファイルと行番号が表示されます。release_mode
- 画面上にエラーカウンタを表示します。UIでエラーを素早く見つけるのに非常に便利です。コンソール下のボタンでトグルできます。gui_editor
- GUIエディタを開きます。ホットキーはControl + F8
任意機能(ホットリロードがあれば通常不要):
reload gui
- すべてのguiファイル、または指定したファイル名があればそのファイルのみをリロードします:reload gui/frontend_main.gui
reload texture
- すべてのテクスチャ、または指定ファイルのみをリロード:reload texture flatmap.dds
その他のヒント:
- エラーログを開いたままにして、コードにミスがないか確認する(同じログフォルダにあります)
- データタイプのログを開いたままにして、テキストエディタのオートコンプリートに使う
- テストにはgui/debugのtest_gui.guiが使えます。このウィンドウを表示するにはコンソールを開いてTest Windowをクリック。閉じるには
GUI.ClearWidgets
コマンドを実行。 - コードを折りたたんで構造を見やすくする。一般的なホットキーはCtrl+K, Ctrl+1(1は折りたたみレベル)
GUI Modの作成[編集 | ソースを編集]
1. ゲームランチャーを起動し、Modライブラリ→Upload Mod→Create a Modへ。タグを含め、すべての項目を入力します。
Createを押すと、Documents/Paradox Interactive/Crusader Kings III/mod
に新しいフォルダと.modファイルが作成されます。
2. 次に、Mod内に「gui」フォルダを作成し、game/guiから改造したいファイルをそこへコピーします。
- どのファイルが必要かわからない場合は、コンソールコマンドgui.debugやGUIエディタでゲーム内から該当箇所を調べます。
GUIの検査[編集 | ソースを編集]
ゲーム内のUI要素は、gui.debugインスペクタかGUIエディタで検査できます。
gui.debugの方が高速ですが、エディタはゲーム内でのインターフェース編集も可能です。とはいえGUIエディタは非常に制限が多く、非推奨です。
どちらの方法でも、目的のguiファイルをテキストエディタで素早く開き、該当行へジャンプできます。これは少し設定が必要ですが(一度やればOKです)。
適切なテキストエディタがない場合は、VSCodeかSublimeをインストールしてください。
ゲームからguiファイルを開くには:
- テキストエディタの.exeを見つけ、右クリックして「パスのコピー」を選ぶ
- Documents\Paradox Interactive\Crusader Kings III のpdx_settings.txtを開く
- "editor"を検索し、その値にエディタのパスを貼り付けます。例:
value="E:\Program Files\Microsoft VS Code\Code.exe"
- その下の"editor_postfix"の値に
:$:1
を追加します。例:value=":$:1"
- 保存します。
postfixは、該当行へジャンプするようエディタに指示するための指定です。
これでゲームを起動し、.guiファイルを素早く開けるようになります。パスはコンソールのsettings
コマンドからも変更できますが、ゲームの再起動が必要です。
GUI Debug[編集 | ソースを編集]
gui.debugはインスペクタを有効にするコンソールコマンドです。
デバッグ情報付きのツールチップを表示し、gui要素の選択、.guiファイルのオープン、該当行へのジャンプを可能にします。
使い方:
-debug_mode -develop
オプション付きでゲームを起動- Esc下の`キーでコンソールを開く
tweak gui.debug
と入力してEnter- tweakerメニューで全オプションのチェックを外し、GUI.Debugにチェック
- 以後はtweakerを開かず、gui.debugコマンドを直接使えます。コンソール下のボタンでもトグルできます。
(他のデバッグオプションは全要素をハイライトして見づらくなるため無効化します)
インスペクタが有効な間、カーソル下のgui要素は緑枠でハイライトされ、ツールチップにファイル名が表示されます。後ろの数字は行番号です。
Alt+左クリックで上下の他要素を選択。
Alt+右クリックでその.guiファイルをテキストエディタで開き、当該行にジャンプします。
任意:
毎回tweakerを開かないよう、コンソールに独自ボタンを追加するのも手です。以下のコマンドを使用します:
onclick = "[ExecuteConsoleCommands('gui.DebugRenderOutsideParent;gui.Debug.DrawUnderMouse;gui.Debug.DrawAll;gui.Debug')]"
これで追加オプションをすべてトグルし、gui.debugを有効化します。次に別ボタンでgui.debugのみをトグルします。
また、ホットキー付きの独自ボタンを作り、scripted widgetでスポーンさせることもできます。詳細は後述のscripted widgets参照。
GUIエディタ[編集 | ソースを編集]
GUIエディタは、ゲーム内でUIを編集するための開発ツールです。
生ファイル編集より敷居が低く見えるかもしれませんが、制約はさらに多いです。
使用するには、-debug_mode
と-develop
オプションを付けてゲームを起動します。
エディタを開く方法:
- Ctrl+F8を押す
- `キー(Escの下)でコンソールを開き、GUI Editorをクリック
- コンソールでgui_editorコマンドを実行
機能
既定ではエディットモードが有効で起動します。上部のウィンドウ(Outliner)で無効化可能です。ホットキー「E」。
- エディットモードはブラウザの検証モードに似ています。有効中はゲームと直接の操作はできませんが、UIパーツを選択し、下部のプロパティウィンドウで変更できます。
- ホイールでフォーカス対象を切り替えます。hud.guiが他ウィンドウの上に重なりがちです。
- 薄い青枠が選択中の要素。ほかの枠を隠すにはOutlinerの「Show Hierarchy」のチェックを外します(ホットキー「L」)。
- 右マウスボタン長押しで選択要素を移動できます。
- Alt+右クリックで該当要素のファイルを開きます。右クリックで誤って要素を動かさないよう注意!
- 元に戻すはCtrl+ZまたはOutlinerのUndo。やり直しはその隣、Ctrl+Y。
- Outlinerの赤い星*は未保存の変更を示します。Ctrl+Sまたは上部の保存ボタンで保存。編集中のguiファイルがMod内にあることを確認してください。でないとゲーム本体フォルダへ書き込みます。(リセットはSteamのファイル整合性の確認)
- 開発用ウィンドウはドラッグで移動、枠のドラッグでリサイズ可能。
- Outlinerの階層でUI要素をドラッグして順序変更できます。右クリックでコンテキストメニュー。
- プロパティウィンドウで、プロパティの変更や(+アイコンから)追加が可能。
Outlinerの「Window」から、UI ComponentsとRegistered Data Typesの2つのウィンドウを開けます。
- UI ComponentsはUIにドラッグできるパレットのようなもの。gui/shared/standard.guiとgui/defaults.guiにボタン、アイコン、テキストなどの基本要素がまとまっています。
- Registered Data Typesは、ゲームデータを表示するために利用可能な関数の参照に使えます。
- Data Types右上のボタンをクリックすると、このデータをログフォルダ(Documents/Paradox Interactive/Crusader Kings III/logs/data_types)にダンプします。
dump_data_types
コマンドでも可。
注意: 誤ってテンプレートを選択しやすく、それを変更するとUI内の「すべての」インスタンスに影響します。Outlinerでどのファイルを選んでいるか注意してください。プロパティウィンドウの青いヘッダーが「type:」で始まっていたらテンプレートなので、意図しない限り編集しないでください。
UIコード[編集 | ソースを編集]
CK3のUIはコンテナと、その中に入るオブジェクトで構成されています。
多くのウィンドウはwindow
コンテナで作られ、マップアイコンはwidgetやhboxを使います。
ファイル内の記述順が画面上の重なり順を決めます。コードの後ろにあるものほど、より上のレイヤーに表示されます。
多くの要素はほかの要素を含められます。たとえば、ボタンの中のアイコンの中にテキストボックスがある、というように。ネストされた要素(子要素)は親と一緒に移動します。
座標は左上(画面または親)の相対位置で指定します。parentanchor
プロパティで変更可能。利用できる値はleft、right、top、bottom、hcenter(水平中央)、vcenter(垂直中央)。parentanchor = right|vcenter
のように|で組み合わせ可能です。
各要素は中括弧で開閉します。例: container = { }
。
一般的なコードスタイルは、ブロックの開始と終了を同じレベルに置き、中身をタブ1つ分インデントします:
widget = { size = { 50 50 } alpha = 0.5 }
これにより構造が見やすくなり、抜け・余分な括弧に気づきやすく、エディタによってはブロック折りたたみのために必要です。
プロモートと関数[編集 | ソースを編集]
各ウィンドウは、利用可能なコマンド(プロモートと関数)のセットをあらかじめ持っています。これらはdump_data_types
コマンド実行後、Documents/Paradox Interactive/Crusader Kings III/logs/data_types
のdata_types*.logにあります。
それらは、プレイヤー名・所持金・子供の数などゲーム内データの表示や、ボタンの動作設定に使われます。
プロモートはスコープ(CharacterやProvinceなどのゲームオブジェクト)を返し、関数は数値・文字列・真偽値などを返します。
グローバルコマンドはどこでも使用できます(例: GetPlayer=プレイヤーキャラを返す、GetCurrentDateなど)。
他のコマンドは対応するウィンドウ/オブジェクト内でのみ使用できます。たとえばGetParentsはキャラクターウィンドウ内でのみ使え、CharacterWindow.GetParents
で始める必要があります。
コマンドは次のようにチェーン可能です:
CharacterWindow.GetCharacter.GetPrimaryTitle.GetHeir.GetPrimarySpouse.GetFather
オブジェクトは親からスコープを継承でき、上記の行を毎回書かずに済みます。例えばウィジェットのdatacontext
にこの行を設定しておけば、その中のテキストボックスは"[Character.GetNameNoTooltip]"
や"[Character.GetGold]"
などを使えます。
同様の仕組みはgridbox内のアイテムにも適用されます。
型変換(キャスト)[編集 | ソースを編集]
スクリプトと違い、UI内の値には整数、固定小数点、浮動小数点などの型があります。
多くはFixedPointToFloatやIntToFixedPointといった関数で別の型に変換できます。これが型キャストです。
例えば、alphaパラメータはfloatを要求するため、必要に応じてキャストします。
数値を文字列にキャストする[編集 | ソースを編集]
(上級者向け。学習中なら読み飛ばしてOK)
現状、数値を文字列に変えるバニラの関数はありません。これは文字列比較や、数値とテキストの連結に必要になることがあります。
回避策は、数値をローカライズに渡し、UI側で文字列として扱わせることです。
以下はプレイヤー年齢の例です:
1. common/customizable_localizationにカスタムローカライズを作成:<syntaxhighlight lang="c"> NumberToString = {
type = all
text = { localization_key = number_to_string }
} </syntaxhighlight>2. guiファイルでその数値を渡します:
raw_text = "[GuiScope.AddScope( 'number', MakeScopeValue(IntToFixedPoint( GetPlayer.GetAge ))).Custom( 'NumberToString' )]"
GetAgeはint32を返し、MakeScopeValueは固定小数点のみ受け付けるため、まずIntToFixedPointでキャストする必要があります。別の型なら適宜調整してください。
3. ローカライズ側で保存した'number'スコープを取得:<syntaxhighlight lang="c"> l_english:
number_to_string: "[SCOPE.GetValue('number')|0]"
</syntaxhighlight>これがUI側へ文字列として渡されます。ローカライズのnumber_to_stringは、実質的に手順2の行全体を置き換える役割です。詳細はカスタマイズ可能ローカライズを参照。
手順2の関数はマクロに置き換えて短く再利用しやすくできます。
そのために、(guiの外側の)data_bindingフォルダに新しいファイルを作ります:<syntaxhighlight lang="c"> macro = {
description = "Returns the int32 as a string." definition = "GetString_int32(Arg0)" replace_with = "GuiScope.AddScope( 'number', MakeScopeValue(IntToFixedPoint(Arg0))).Custom('NumberToString')"
}
</syntaxhighlight>これで"[GetString_int32( GetPlayer.GetAge )]"
や"[GetString_int32( '(int32)2' )]"
のように使えます。
UIコンポーネント[編集 | ソースを編集]
これはすべてのウィンドウを構成する基本要素です。ゲームにはこれらを基にした多くの定義済みタイプがあり、gui/sharedにあります。
一部はUIライブラリウィンドウでプレビューできます。開くには、コンソールでrelease modeをトグルすると、上にUI Libraryボタンが出ます。
window
- 可動のコンテナ。移動を有効化するには
movable = yes
を追加。 - 固定サイズにも、子要素に合わせてリサイズにもできます。
- ゲーム内では
using = Window_Background
やusing = Window_Decoration
のようなテンプレートで背景を設定します。 - 子要素がウィンドウ外にあるとクリックやツールチップが効きません。
allow_outside = yes
で変更可能。 - 同レイヤーの他ウィンドウより手前に出すには、クリックで前面化します。順序操作には
PdxGuiWidget.StackTop
やPdxGuiWidget.StackBottom
を使用。
widget
- windowに似た静的コンテナ。クリックしても前面には出ません。
margin_widget
- widgetに似ていますが、マージンでリサイズ可能。(画面サイズに応じてリサイズするウィンドウを、高さ100%・マージン約50のように設定してHUDを見せるなどが可能)
container
- 固定サイズを持ちません(maximumsizeは設定可)。
- 非表示要素も含め、子要素全体に合わせて自動リサイズ。
ignoreinvisible = yes
で非表示を無視可能。 - 複数要素をまとめて移動するためによく使われます。
flowcontainer
- 子要素を横方向に並べ、全体に合わせてリサイズ。
direction = vertical
で縦に。 - 既定では非表示の子要素も無視しません。
ignoreinvisible = yes
で変更。 - 固定サイズ不可。
- 子要素は自動配置されるため位置指定不可。
- 位置調整が必要なら、子をcontainerやwidgetで包み、その親に対する相対位置を調整します。
hbox
/vbox
- 子要素を横一列に並べ、幅に沿って配置。vboxは縦版。
- 固定サイズは持てず、子要素に合わせて、または親サイズに合わせてリサイズ(レイアウトポリシー次第)。
- minimumsize、maximumsize、min_width、max_width、marginsで制限可能。
- 既定では非表示の子要素を無視。
ignoreinvisible = no
で変更可能。 - データモデル(ゲームデータのリスト化)を受け取れます。
dynamicgridbox
- データモデル専用。
- アイテムを縦に並べます。
flipdirection = yes
で横に。 - 既定では非表示アイテムを無視しません。
ignoreinvisible = yes
で変更。 - コンテンツに合わせてリサイズし、minimumsize/maximumsizeで制限。
- アイテムは異なるサイズ可。
- 非常に長いリストでは重くなりがち。
fixedgridbox
- dynamic版に似ていますが、すべてのアイテムが固定サイズ(実質テーブル)。
- データモデル専用。
- アイテムを縦に並べます。
flipdirection = yes
で横に。 - 非表示アイテムを無視できません。
- 固定サイズにも、コンテンツに合わせたリサイズにもでき、minimumsize/maximumsizeで制限可能。
- 長いリストではパフォーマンスに優れます。
overlappingitembox
- データモデル専用。
- アイテムを横方向に並べ、ボックスサイズを超えると重ねて表示します。
flipdirection = yes
で縦に。 - 固定サイズにも、自動リサイズにもできます。
scrollarea
- コンテンツがサイズを超えるとスクロールバーが出るウィジェット。
scrollbarpolicy_horizontal = always_off
およびscrollbarpolicy_vertical = always_off
でスクロールバーを無効化可能。- 固定サイズにも、コンテンツに合わせてリサイズにもでき、minimumsize/maximumsizeで制限可能。
- ゲームファイルでは主に
scrollbox
タイプ(背景・スクロールバー・マージン付きのscrollarea)を使います。
button
- クリック可能なオブジェクト。
onclick
やonrightclick
を受け付けます。- 右クリック機能を追加する場合、
button_ignore = none
を含めてください。
- 右クリック機能を追加する場合、
- 既定ではテクスチャなし。
- 固定サイズにも、子要素に合わせてリサイズにもできます。
- サイズのないボタンは、不可視ホットキーの追加に使えます。
icon
- テクスチャを表示。
- 子要素を持つウィジェットとしても使えます。
mirror = horizontal
やmirror = vertical
で反転可能。
textbox
- テキストを表示します。
- 固定サイズまたは自動サイズ変更が可能です。
- 長すぎるテキストを切り詰めるには、
elide = right
またはelide = left
を使用します。 multiline = yes
を使えば、1行にも複数行にもできます。- ゲームのファイルでは主に gui/shared/text.gui で定義されたタイプ(例:
text_single
)を使います。見た目の一貫性を保ち、毎回のコード量を減らすために活用してください。
hbox/vbox[編集 | ソースを編集]
hbox と vbox は、子要素を並べたりサイズ変更したり(あるいは均等に広げたり)できるリサイズ可能なコンテナです。hbox は子要素を横方向、vbox は縦方向に並べる点だけが異なり、それ以外の動作は同じです。そのため、以下の例は両方に当てはまります。
これらは自分自身と子要素を自動的に中央揃えにします。parentanchor は使用しないでください。レイアウトが崩れます。代わりに expand={}
を使って片側へ押しやります。例は以下を参照してください。
ほとんどのウィンドウは、内容を縦に配置するために vbox を使用します。経験則として、vbox には拡張ポリシーを設定し、その後に expand={}
を使いましょう。これでレイアウトの問題の 90% は解決します。
重要: 大きなサイズのオブジェクトはボックスを引き伸ばし、レイアウトを崩すことがあります。これは特にドイツ語やロシア語の長いテキストで、バニラ環境でよく起こります。
テキストに max_width を設定し、とても長い文字列でテストしてください。大量のダミーテキストを挿入するには、LOREM_IPSUM_TITLE と LOREM_IPSUM_DESCRIPTION のローカライズキーを使います。
詳細な挙動:
以下のスクリーンショットでは、hbox の背景は黒です。すべての例は UI Library mod で利用できます。
固定サイズの親に配置した場合、デフォルトでは親のサイズいっぱいまで水平方向・垂直方向の両方に広がります。しかし、他の vbox/hbox の中に配置した場合は、親のサイズいっぱいには広がりません。
レイアウトポリシー[編集 | ソースを編集]
レイアウトポリシーは、hbox/vbox が子要素をどのようにリサイズするかを制御します。ボックスの中にさらにボックスがある場合にも適用されます。
種類は layoutpolicy_horizontal と layoutpolicy_vertical の2つで、それぞれ横方向・縦方向の挙動を制御します。
ポリシーは5種類あり、デフォルトは fixed です。
- fixed - 元のサイズを維持します。それ以上大きくも小さくもなりません。"fixed" の hbox/vbox はコンテナのように、子要素に合わせてサイズ変更します。
- expanding - 親の幅/高さまで広がり、元のサイズより小さくはなりません。他のポリシーの子要素より優先されます。複数の子要素が "expanding" の場合、利用可能なスペースを等分します。
- growing - 動作は "expanding" と同じですが、優先度が低いです。"expanding" の子要素がある場合、"growing" は拡大しません。つまり、expand = {} ウィジェットは 0 に縮むため、"expanding" と併用したい場合はポリシーを変更してください。
- preferred - 利用可能なスペースに応じて拡大・縮小します。
- shrinking - 元のサイズより小さくできますが、それ以上大きくはできません。
レイアウトポリシーは minimumsize、maximumsize、min_width、max_width も尊重します。
アニメーションステート[編集 | ソースを編集]
アニメーションは state
を使って次のように作成できます: <syntaxhighlight>
state = {
name = _show alpha = 0.5 duration = 0.5
} </syntaxhighlight>このステートは、オブジェクトが表示されるときに自動的にトリガーされ、0.5秒かけてアルファ値を50%にします。
ステートでは以下が可能です:
- サイズ、位置、アルファなどのプロパティを変更
start_sound = { soundeffect = "event:..." }
でサウンドを再生onclick
の代わりにon_start
やon_finish
を使って、ボタンに似た関数を実行
on_start
はアニメーションの開始時にトリガーされます。
on_finish
は、duration が設定されている場合は終了時にトリガーされます。設定されていない場合は on_start
と同様に即時です。
既知の問題: on_start
は現在バグがあり、2回トリガーされます。可能な限り on_finish
を使用してください。
ステート名
自動的にトリガーされるあらかじめ定義された名前がいくつかあります:
- _show - オブジェクトが表示状態になったときにトリガー。これはウィジェット自身にのみ発火し、その子要素には発火しない点に注意
- _hide - オブジェクトが非表示になったとき
- _mouse_hierarchy_enter - このウィンドウまたはボタン上にカーソルが置かれたとき
- _mouse_hierarchy_leave - カーソルがこのウィンドウまたはボタンから離れたとき
- _mouse_press - このボタンが押されたとき
- _mouse_click - このボタンが押されて離されたとき
- _mouse_release - ボタンが離されたとき
- daily_tick - 毎日トリガー
- monthly_tick - 毎月トリガー
一部のウィンドウには専用のステート名があります。例えば、戦闘ウィンドウの phase_change
や new_battle_event
などです。
ステートのトリガー
ステートは任意の名前を与えて手動でトリガーできます。
TriggerAnimation
はスコープされたオブジェクト内の、指定名のステートを1つトリガーします。
PdxGuiTriggerAllAnimations
は、画面上で可視状態にある同名のすべてのステートをトリガーします。
例:
onclick = "[PdxGuiWidget.TriggerAnimation('my_state')]"
- ボタン自身に設定されたステートをトリガーします。
onclick = "[PdxGuiWidget.AccessParent.FindChild('widget_with_state').TriggerAnimation('my_state')]"
- ボタンの親に移動し、'widget_with_state' という子を見つけ、そのステートをトリガーします。階層を上に戻るには AccessParent.AccessParent
を連結する必要がある場合があります。ただし FindChild
は複数階層を横断して検索できます。
onclick = "[PdxGuiTriggerAllAnimations('my_state')]"
- 同名のステートをすべて(他の可視ウィンドウ内にあるものも)トリガーします。
既知の問題: TriggerAnimation
や PdxGuiTriggerAllAnimations
が使用された時点でオブジェクトが不可視の場合、そのステートは後で可視になったときにトリガーされます。
自動トリガー
条件が満たされたときに自動でトリガーさせることもできます。
trigger_on_create = yes
- ウィンドウが最初に作成されたときにトリガーされます。可視状態の変更ではトリガーされませんが、一般的には親ウィジェットが可視になったときにトリガーされます。
trigger_when
- 条件が満たされたときにトリガーされます。
なお、trigger_when
は手動トリガーを防ぎません。イベントのトリガーのようには機能せず、独自の on_action に近いものです。
ベジエ
duration を持つステートでは、ベジエ曲線を使って変化速度を制御し、イージングを加えることができます。
例えば、ゲーム内の多くのウィンドウで使われるテンプレート Animation_Curve_Default では次のベジエ曲線が使われています:
bezier = { 0.25 0.1 0.25 1 }
数値は制御点の座標2組です。画像を参照してください。
この曲線は、ウィンドウがわずかな遅延ののちに素早く表示され、最後に 100% へと滑らかに到達することを意味します。
効果は強くはありませんが、より自然な感覚を生み出す助けになります。
異なるベジエ曲線を試すにはこのサイトを使ってください: https://cubic-bezier.com/#.25,.1,.25,1
簡単に言えば、両極端は次のとおりです:
{ 0 1 1 0 }
は素早く表示
{ 1 0 0 1 }
はゆっくり表示
テンプレート[編集 | ソースを編集]
テンプレートとタイプは、ボタンやウィンドウ背景、テキストスタイルなど、コード全体で何度も使える名前付きのコードブロックです。スタイルを統一し、記述量を減らすのに役立ちます。
テンプレートはウィンドウ全体の内容を格納することも、1行だけの内容であることもあります。例えば次のようなものです:
template Window_Size_Sidebar { size = { 610 100% } }
このテンプレートは "using = Window_Size_Sidebar" で使用できます。実質的に "using" 行がテンプレートの内容に置き換わります。
テンプレートはグローバルで、任意の .gui ファイルに定義できます。ゲームのテンプレートの多くは gui/shared に保存されています。ローカル版の local_template は、同じファイル内で定義する必要があります。
よく使われるテンプレートやタイプは UI Library に掲載されています。アクセスするにはコンソールを開き、Release Mode をオンにすると "UI Library" という新しいボタンが表示されます。
タイプ[編集 | ソースを編集]
テンプレートは1つのプロパティのように小さくできる一方で、タイプは常にボタンやウィジェットのような一つの要素全体です。
text_single と text_multi は、すでに多くのプロパティが定義されたテキストボックスのタイプで、毎回書き直す代わりに次のように簡潔に書けます:
text_single = { text = "my text" }
タイプは少し異なる方法で定義します。まずタイプのグループに名前を付けて作成します:
types Standard_Types { type text_single = textbox { ... } }
グループ名は何でもよく、動作に影響はありません。
Blockoverride[編集 | ソースを編集]
テンプレートとタイプには、名前付きの override ブロックを持たせることができ、インスタンス全体を変更せずに一部だけを編集できます。例えば、テンプレートにデフォルトのテキストブロックがあるとします:
block "text" { text = "default_text" }
これを置き換えるには、同じ名前の blockoverride をインスタンスに追加します:
blockoverride "text" { text = "actual text" }
インスタンスから削除することもできます: blockoverride "text" {}
タイプの置換[編集 | ソースを編集]
個々のテンプレートやタイプを、バニラのファイル全体を上書きせずに置き換えることができます。
そのためには、アルファベット順で最初に来る新しいファイルを作成します。例えば 00_ で始めます。例: 00_my_types.gui。
タイプを置き換える場合は、まず任意の名前でグループを定義するのを忘れないでください。その中でタイプを定義します。
テンプレートなら、テンプレート定義を書くだけで、他に何も追加する必要はありません。
例。button_standard_small のデフォルトサイズを変えたいとします。新しいファイル 00_small_button.gui を作成して、次のように記述します: <syntaxhighlight lang="c"> types SmallButton {
type button_standard_small = button_standard { size = { 40 25 } }
} </syntaxhighlight>
Mod 互換性の追加[編集 | ソースを編集]
2つの Mod が同じ GUI ファイルを上書きし、同時に読み込むと競合するのは一般的です。この場合、読み込み順で後の Mod によるカスタマイズのみがゲーム内に反映されます。
Mod 製作者は GUI タイプやテンプレートを使い、互いの Mod 内に「フック」を作ることで互換性を確保できます。
そのために、どちらか(または両方)の製作者が、相手の Mod のタイプ/テンプレートの使用箇所を、自分の Mod で編集した .gui
ファイル内に含めます。
例えば、Mod 製作者が some_other_mods_type = {}
や using = some_other_mods_template
を window_character.gui
などの修正済みバニラファイルに追加します。
この Mod が、そのタイプやテンプレートを定義している Mod と一緒に読み込まれた場合、それがウィンドウに表示されます。そうでない場合、その行は見た目に影響を与えず、起動時に一度だけ error.log
に単一のエラーが記録されます。
したがって、バニラの .gui
ファイルに加えた独自の追加要素は、たとえ自身の Mod で1回しか使わないとしても、別のカスタム .gui
ファイル内のタイプ/テンプレートに抽出しておくのが望ましい実践です。そうすることで、他の Mod 製作者はあなたのタイプ/テンプレートを自分のコードに挿入するだけで、あなたと連携せずとも互換性を実現できる可能性があります。
Datamodels[編集 | ソースを編集]
Datamodel はリストを表示するために使われます。例:
datamodel = "[CharacterWindow.GetChildren]"
Datamodel は vbox、hbox、flowcontainer、dynamicgridbox、fixedgridbox、overlappingitembox で表示できます。
ウィジェットは次のようにリストから単一の項目を表示することもできます: <syntaxhighlight lang="c"> datacontext_from_model = { datamodel = "[EventWindowData.GetOptions]" index = "1" } </syntaxhighlight>
多くのバニラのリストはハードコードされており、項目の追加・削除・ソート変更はできません。
ただし、リスト内の一部の項目は visible = "[]"
パラメータで非表示にできます。次の2点に注意してください:
- fixedgridbox はセルを動的にリサイズしないため、空白が残ります。
- 複数行や複数列の dynamicgridbox でも空白が生じます。
カスタムソートを作るには、スクリプトで同じリストを変数リストとして用意し、ordered_in_list を使ってソートする必要があります。
参考として Advanced Character Search mod を参照してください。
変数リストを表示するには、[GetPlayer.MakeScope.GetList('list_name')]
またはグローバル変数リストには [GetGlobalList]
を使います。
プレイヤーに保存されていない場合は、CharacterWindow.GetCharacter.MakeScope...
のように適切なオブジェクトにスコープしてください。
詳細は下記を参照。
Datamodel と Datacontext を混同しないでください!
Datacontext は通常、[CharacterWindow.GetCharacter]
のように単一のプロモート、つまりゲームオブジェクトを参照します。
珍しい例外の一つがキャラクターウィンドウの特性リストです:
datacontext = "[CharacterWindow.GetTraitArrays]" datamodel = "[TraitArrays.GetPersonalityTraits]"
スクリプト化 GUI[編集 | ソースを編集]
スクリプト化 GUI は本質的には、UI からトリガーされる隠しイベントです。
それらは game/common/scripted_guis の .txt ファイルとして保存されます。
最も単純なスクリプト化 GUI は次のようになります: <syntaxhighlight lang="abap"> my_sgui = {
effect = { add_gold = 100 }
} </syntaxhighlight>UI では次のように、プレイヤーをスコープして使用できます:
onclick = "[GetScriptedGui('my_sgui').Execute( GuiScope.SetRoot( GetPlayer.MakeScope ).End )]"
every_player = { add_gold = 100 }
のようにグローバルな効果を使う sgui なら、スコープなしで使えます:
onclick = "[GetScriptedGui('my_sgui').Execute( GuiScope.End )]"
他のオプションパラメータは以下のとおりです:
gui_name = { scope = character # ルートスコープ、つまり効果の対象 saved_scopes = {} # 追加の対象 confirm_title = "your_title" # これを追加すると、実行前に確認ダイアログが表示される confirm_text = "your_text" # 確認ダイアログの追加テキスト effect = { # 実行内容 custom_tooltip = "" # ツールチップを追加 } is_shown = {} # UI 上で表示されるか? is_valid = {} # プレイヤーが使用可能か? ボタンの enabled を使わなくても常にチェックされる ai_is_valid = {} # AI が使用可能か? デフォルトでは無効 }
すべてのブロックが必要なわけではありません。scripted gui は is_shown や is_valid だけを含むこともあります。
常に sgui を参照する代わりに、datacontext で一度宣言しておけば、そのオブジェクトやその子で使われる他の関数は、その sgui を使用します:
datacontext = "[GetScriptedGui('gui_name')]" onclick = "[ScriptedGui.Execute( GuiScope.SetRoot( GetPlayer.MakeScope ).End)]" visible = "[ScriptedGui.IsShown( GuiScope.SetRoot( GetPlayer.MakeScope ).End)]" enabled = "[ScriptedGui.IsValid( GuiScope.SetRoot( GetPlayer.MakeScope ).End)]" tooltip = "[ScriptedGui.BuildTooltip( GuiScope.SetRoot( GetPlayer.MakeScope ).End)]"
GetPlayer.MakeScope
の代わりに、キャラクターウィンドウ内のキャラクター CharacterWindow.GetCharacter.MakeScope
のように別のゲームオブジェクトにスコープすることもできます。あるいは sgui のルートが州(province)なら、HoldingView.GetProvince.MakeScope
です。
ScriptedGui.Execute
は effect
ブロックに記述されたすべてを実行します。ボタンの onclick
やアニメーションステートの on_start
/on_finish
と一緒に使います。
IsShown
と IsValid
は、それぞれ is_shown と is_valid ブロックの条件をチェックします。どちらのブロックも true/false を返すだけで、AddTextIf や Select_CString など他の関数でも使えます。
BuildTooltip
はテキストボックスで使用して、ツールチップをテキストとして表示することもできます。
スクリプト化 GUI に別スコープを追加するには、次のように AddScope を使用します:
"[ScriptedGui.Execute( GuiScope.SetRoot( GetPlayer.MakeScope ).AddScope( 'target', CharacterWindow.GetCharacter.MakeScope ).End )]"
これで sgui 内では scope:target
として参照できます。名前は任意です。
このようにして複数のスコープを保存できます: AddScope().AddScope().AddScope().End
追加したスコープを saved_scopes に宣言する必要はありません。宣言すると、ゲームは常にそれらをチェックし、GUI ファイルで追加されていなければ sgui は動作しません。
MakeScopeValue
、MakeScopeFlag
、MakeScopeBool
を使えば、UI から sgui に値・テキスト・ブール値を渡すこともできます。
例:
onclick = "[GetScriptedGui('give_gold').Execute( GuiScope.SetRoot( GetPlayer.MakeScope ).AddScope( 'balance', MakeScopeValue(GetPlayerBalance) ).End )]"
数値は他の保存スコープと同様に参照されます: add_gold = scope:balance
MakeScopeValue は固定小数点値を想定しているため、事前に IntToFixedPoint で値を変換する必要があるかもしれません。
数値を直接渡すこともできます: MakeScopeValue('(CFixedPoint)25')
重要: ドットや開き括弧の前にスペースを入れないでください!Execute(
は正しく、Execute (
は間違いです。他のスペースは省略できますが、可読性のために残すと良いでしょう。
変数やスクリプト値の表示[編集 | ソースを編集]
変数やスクリプト値は、次のようにUIに表示できます。
変数:
text = "[GetPlayer.MakeScope.Var('var_name').GetValue|1]"
スクリプト値(common/script_values で定義):
text = "[GetPlayer.MakeScope.ScriptValue('sval_name')|0]"
AddScope で別のスコープを追加できる代替方法:
text = "[GuiScope.SetRoot( GetPlayer.MakeScope ).AddScope( 'target', CharacterWindow.GetCharacter.MakeScope ).ScriptValue('sval_name')|0]"
これらの例では、プレイヤーキャラクターが変数を持ち、svalue のルートとして機能します。MakeScope を使える限り、他のプロモートも使用可能です。サポートされているかはデータ型のログを検索してください(例: Character.MakeScope)。
末尾の |1 は任意で、小数点以下1桁に切り捨てます。つまり 1.573 は 1.5 と表示されます。これは任意の桁数に設定でき、% を付けるとパーセンテージに変換、= または + を付けると値が正負の場合に色付けできます。
|O は整数と併用して序数表示ができます。['(int32)2'|O]"
は 2nd
と表示されます。注意: 数字のゼロではなくアルファベットの大文字 O です。
スクリプト値を整数に変換するには FixedPointToInt を使います。
UI に表示されるスクリプト値は毎フレーム計算されるため、アイテムのリストが大きかったり、svalue の計算が重い場合はパフォーマンスに影響することがあります。その場合は変数を使う方が良いでしょう。
イベントで値を表示するためにローカライズを使う場合は、次のようにします:
event_var: "[ROOT.GetCharacter.MakeScope.Var('test_var').GetValue|0]"
event_value: "[SCOPE.ScriptValue('test_value')|0]"
保存済みスコープ(ここでは "target")がある場合は、こうなります:
event_var: "[target.MakeScope.Var('test_var').GetValue|0]"
event_value: "[GuiScope.SetRoot( target.MakeScope ).ScriptValue('test_value')|0]"
データリストの表示[編集 | ソースを編集]
たとえば社会集団を作るために、キャラクターのカスタムリストを作成できます。
これを行うには、まず変数リストに追加します。イベントやスクリプト化GUIを通じて、次のように行えます:
effect = { every_living_character = { limit = { has_trait = paranoid } root = { add_to_variable_list = { name = secret_society target = prev } } } }
このエフェクトをプレイヤーに発火すると、彼らが root
となり、リストはそこに保存されます。
次に、任意のリストボックス(vbox、dynamicgridbox、fixedgridbox)を使い、datamodel をリストに設定します。
dynamicgridbox = { datamodel = "[GetPlayer.MakeScope.GetList('secret_society')]" item = { flowcontainer = { datacontext = "[Scope.GetCharacter]" portrait_head_small = {} text_single = { text = "[Character.GetNameNoTooltip]" } } } }
アイテムにアクセスするには、Scope
と、対象オブジェクトに対応する関数(GetCharacter
や Title
など)を使います。利用可能な Scope
関数は Data Types を確認してください。datacontext で一度宣言すれば、その後は Character
を使い続けられます。
注意: datacontext は item = {}
ブロックの中ではなく、そこで使うウィジェット(ボタン、テキスト、ここではフローコンテナ)の中に置いてください。
新しいウィンドウとトグル[編集 | ソースを編集]
新しいウィンドウは別のウィンドウ内に追加することも、別ファイルで作成してスクリプト化ウィジェットとして生成することもできます。
ウィンドウの表示/非表示は、変数と Scripted GUI、または UI Variable System だけで制御できます。
ただし、新しいウィンドウを追加するタイプのMODは互換性が難しくなります。既存ファイルのどこかにウィンドウを開くボタンを追加する必要があるためです。
代わりに、決断・イベント・キャラクターインタラクションでウィンドウを開くこともできますが、HUD上のボタンと比べると利便性は下がります。
スクリプト化ウィジェットとしてウィンドウを作成[編集 | ソースを編集]
任意の名前で新しい gui ファイル(例: gui/new_window.gui
)を作成します。
その中に次のようにウィンドウを作成し、任意のカスタム名を付けます。<syntaxhighlight> window = { name = "my_window" layer = top using = Window_Size_MainTab using = Window_Background_Sidebar } </syntaxhighlight>gui/ フォルダに "scripted_widgets" というフォルダを新規作成します。
その中に任意の名前の txt ファイル(例: gui\scripted_widgets\scripted_windows.txt
)を作ります。
そこに、先ほどの gui ファイルとウィンドウ名を追加します:
gui/new_window.gui = my_window
ゲームがマップビューまでロードされると、自動的にウィンドウが作成されます。
複数のウィンドウ(その他のウィジェットやボタンも可)を作成でき、各行に1つずつ追加します。例:<syntaxhighlight> gui/new_window.gui = my_second_window gui/my_shortcuts.gui = my_button etc... </syntaxhighlight>
ウィンドウの表示切替[編集 | ソースを編集]
ウィンドウは UI 変数システム、変数、Scripted GUI で切り替えられます。
UI システム
ウィンドウを隠す:
visible = "[GetVariableSystem.Exists('show_my_window')]"
ボタンの例:
onclick = "[GetVariableSystem.Toggle('show_my_window')]"
UI システムは最も手早く設定できますが、ゲームを終了すると全てのトグルがリセットされます(変数と異なり)。
変数と SGUI
ウィンドウを隠す:
visible = "[GetPlayer.MakeScope.Var('show_my_window').IsSet]"
ボタンの例:
onclick = "[GetScriptedGui('toggle_my_window').Execute( GuiScope.SetRoot( GetPlayer.MakeScope ).End )]"
そして common/scripted_guis
に次の Scripted GUI を用意します。<syntaxhighlight>
toggle_my_window = {
effect = { if = { limit = { has_variable = show_my_window } remove_variable = show_my_window } else = { set_variable = show_my_window } }
} </syntaxhighlight>別々の SGUI に分けて、変数を設定するものと削除するものを作っても構いません。
変数はイベントや決断から設定することもできます。
SGUI
より複雑なトリガーには Scripted GUI も使えます。
この場合、ウィンドウを隠すには:
visible = "[GetScriptedGui('show_my_window').IsShown( GuiScope.SetRoot( GetPlayer.MakeScope ).End )]"
そして次のような Scripted GUI を用意します。<syntaxhighlight> show_my_window = {
is_shown = { # various triggers is_adult = yes is_female = yes is_landed = yes }
} </syntaxhighlight>ここでは変数と Scripted GUI がプレイヤーをスコープしています。代わりに別のオブジェクトやグローバル変数/SGUI を使うこともできます。例えば:
visible = "[GetGlobalVariable('show_my_window').IsSet]"
visible = "[GetScriptedGui('show_my_window').IsShown(GuiScope.End)]"
このウィンドウはプレイヤーがキャラクターを選択する前に作成される点に注意してください。そのため、プレイヤーへスコープする際は、まずプレイヤーが存在するかをチェックする必要があるかもしれません。
例えば、100% サイズの不可視ウィジェットを設定し、visible = "[GetPlayer.IsValid]"
と alwaystransparent = yes
を付けて、クリックを透過させるようにできます。
その中に、変数や SGUI のチェックを行う実際のウィンドウを置きます。
他にもウィンドウの作成や切り替え方法はいくつかありますが、やや面倒です。
- PdxGuiWidget - 単純だが、トグルが複数だと複雑になる
- アニメーション - 記述は長くなるが、複数の処理をまとめてトリガーしやすい
- コンソールコマンド
GUI.CreateWidget
- コンソールはマルチプレイでは使えず、実績も無効化されます。
以下は以前の例です。
PdxGuiWidget によるトグル[編集 | ソースを編集]
PdxGuiWidget は、名前付き要素の表示/非表示に使うシンプルな関数です。
この例では、隠れたサブメニューを持つコンテナと、それを表示するボタン、隠すボタンがあります。
- 1つ目のボタンはクリックされると親に戻り、サブメニューともう一方のボタンを探して表示し、自分自身は隠れます
- 2つ目のボタンは要素とボタンを探してそれらを表示し、自分自身は隠れます
container = { button = { name = "show submenu" onclick = "[PdxGuiWidget.AccessParent.FindChild('submenu').Show]" onclick = "[PdxGuiWidget.AccessParent.FindChild('hide submenu').Show]" onclick = "[PdxGuiWidget.Hide]" } button = { name = "hide submenu" visible = no onclick = "[PdxGuiWidget.AccessParent.FindChild('submenu').Hide]" onclick = "[PdxGuiWidget.AccessParent.FindChild('show submenu').Show]" onclick = "[PdxGuiWidget.Hide]" } widget = { name = "submenu" visible = no } }
要素同士がさらに親子で離れている場合は、次のように AccessParent を繰り返せます:
onclick = "[PdxGuiWidget.AccessParent.AccessParent.AccessParent.AccessParent.FindChild('submnenu').Show]"
各ボタンは、タイプにかかわらず複数の要素を表示・非表示にできます。必要なのは名前だけです。
長所:
- 単純なトグルなら設定が簡単
短所:
- ゲームを再起動するたびにトグルはリセットされる
- 複数の要素やトグルを扱うとコードが膨らみ管理が難しくなる
- データリスト(dynamicgridbox など)の項目を隠そうとすると、最初のインスタンスしか隠れない
アニメーションによるトグル[編集 | ソースを編集]
ボタン(や条件)でトリガーされるアニメーションを設定して、要素の表示/非表示や移動まで行えます。こうすることで、ボタンとウィンドウの間にどれだけ親があるかを数える必要がなくなり、1つの onclick で多くの処理を同時に起動できます。
前の例は次のようになり、動作は同じです。1つ目のボタンは "show_submenu" をトリガーし、自身を隠して残りを表示、2つ目のボタンは "hide_submenu" をトリガーし、自分とウィジェットを隠し、1つ目のボタンを表示します。
container = { button = { state = { # これはアニメーションです name = show_submenu on_start = "[PdxGuiWidget.Hide]" } state = { name = hide_submenu on_start = "[PdxGuiWidget.Show]" } onclick = "[PdxGuiTriggerAllAnimations('show_submenu')]" } button = { visible = no state = { name = show_submenu on_start = "[PdxGuiWidget.Show]" } state = { name = hide_submenu on_start = "[PdxGuiWidget.Hide]" } onclick = "[PdxGuiTriggerAllAnimations('hide_submenu')]" } widget = { visible = no state = { name = show_submenu on_start = "[PdxGuiWidget.Show]" } state = { name = hide_submenu on_start = "[PdxGuiWidget.Hide]" } } }
やや長くなりますが、アニメーションはテンプレートとして保存し、using = hide_animation
の1行で再利用できます。Fullscreen Barbershop ではアニメーションが広く使われています。より良い例が必要ならそちらを参照してください。
長所:
- 多くの要素をまとめてリンクしやすく、別ウィンドウを開いてその中のアニメーションを起動することも可能
短所:
- アニメーションブロックはかなり長くなりがち
- ゲームを再起動すると全てのトグルがリセットされる
システム変数[編集 | ソースを編集]
システム変数はゲーム内部で使用され、セーブに保持されず、スクリプトから直接アクセスすることはできません。
.gui ファイル内で直接作成できるため、セットアップは不要です。
システム変数の構文:
onclick = "[GetVariableSystem.Toggle( 'var_name' )]"
または:
datacontext = "[GetVariableSystem]" onclick = "[VariableSystem.Toggle( 'var_name' )]"
利用可能な関数:
- Clear -
Clear( 'var_name' )
変数をクリア - ClearIf -
ClearIf( 'var_name', Condition )
条件が真なら変数をクリア - Exists -
Exists( 'var_name' )
ブール、変数が存在すれば true - Get -
Get( 'var_name' )
CString、変数に保存された文字列を返す - HasValue -
HasValue( 'var_name', 'string' )
ブール、与えた文字列を持っていれば true - Set -
Set( 'var_name', 'string' )
変数を指定の文字列に設定 - Toggle -
Toggle( 'var_name' )
存在すればクリア、なければ作成 - SetOrToggle -
SetOrToggle( 'var_name', 'string' )
同じ文字列ならクリア、そうでなければ指定の文字列に設定
システム変数でのトグル[編集 | ソースを編集]
このファイル内での基本的なトグルは次のようになります:
container = { button = { onclick = "[GetVariableSystem.Toggle( 'gui_toggle' )]" } widget = { visible = "[GetVariableSystem.Exists( 'gui_toggle' )]" } }
クリックされると、システム変数は存在有無に応じてトグルされ、その結果がウィジェットの表示/非表示に使われます。
システム変数でのタブ[編集 | ソースを編集]
3つのタブの基本設定は次のとおりです:
container = { button = { onclick = "[GetVariableSystem.Set( 'gui_tabs', 'tab_1' )]" } button = { onclick = "[GetVariableSystem.Set( 'gui_tabs', 'tab_2' )]" } button = { onclick = "[GetVariableSystem.Set( 'gui_tabs', 'tab_3' )]" } widget = { visible = "[GetVariableSystem.HasValue( 'gui_toggle', 'tab_1' )]" } widget = { visible = "[GetVariableSystem.HasValue( 'gui_toggle', 'tab_2' )]" } widget = { visible = "[GetVariableSystem.HasValue( 'gui_toggle', 'tab_3' )]" } }
変数は最初は値を持たないため、いずれのウィジェットも表示されません。
デフォルトのタブを設定するには、ウィンドウを開くボタンで変数を設定します:
button = { onclick = "[GetVariableSystem.Toggle( 'gui_toggle' )]" # これでウィンドウを開く onclick = "[GetVariableSystem.Set( 'gui_tabs', 'tab_1' )]" # これでデフォルトタブを設定 }
または、ウィンドウが表示されたときの state ブロックを使います:
state = { name = _show on_start = "[GetVariableSystem.Set( 'gui_tabs', 'tab_1' )]" }
あるいは、変数が存在しないときに表示されるように1つのウィジェットを設定し、初期値の設定を避けることもできます:
container = { button = { onclick = "[GetVariableSystem.Clear( 'gui_tabs' )]" } button = { onclick = "[GetVariableSystem.Set( 'gui_tabs', 'tab_2' )]" } button = { onclick = "[GetVariableSystem.Set( 'gui_tabs', 'tab_3' )]" } widget = { visible = "[Not( GetVariableSystem.Exists( 'gui_toggle' ) )]" } widget = { visible = "[GetVariableSystem.HasValue( 'gui_toggle', 'tab_2' )]" } widget = { visible = "[GetVariableSystem.HasValue( 'gui_toggle', 'tab_3' )]" } }
これは、最初の例を別の方法でデフォルト値を設定したものと同等です。
長所:
- シンプルで覚えやすい構文
- 複数の要素、別ウィンドウ間でもリンクしやすい
- 追加のコマンド(下記参照)でまったく新しいウィンドウの表示にも拡張でき、hud.gui にウィジェットを置く必要がなくなる
短所:
- スクリプトと直接やり取りできず、GUI から設定・クリアする必要がある
- 管理が難しくなることがある
- ゲームを再起動するとすべてのトグルがリセットされる
新しいウィジェットの作成[編集 | ソースを編集]
ExecuteConsoleCommand( ... )
コマンドを使うと、まったく新しいウィンドウを作成できます。
まず、表示するための .gui ファイル内にウィンドウを作成します。例: "gui/custom_windows/my_window.gui"。メインウィンドウに名前を付けておきます。
window = { name = "my_custom_window" parentanchor = center layer = middle size = { 100 100 } using = Window_Background }
上記は画面中央に 100 x 100 のウィンドウを作成します。重要なのは名前で、これがウィンドウ作成時に使われます。
ウィンドウを作成するボタンは次のようになります:
button = { onclick = "[ExecuteConsoleCommand('gui.createwidget gui/custom_windows/my_window.gui my_custom_window')]" }
閉じるには:
button = { onclick = "[ExecuteConsoleCommand('gui.ClearWidgets my_custom_window')]" }
gui.ClearWidgets と my_custom_window の間はスペース 1 つだけにしてください。スペースが 1 つより多いと、gui.ClearWidgets は my_custom_window だけでなくコンソールで作成したすべてのウィジェットをクリアしてしまいます。
あるいはトグルとしてまとめることもできます:
button = { onclick = "[ExecuteConsoleCommand( Select_CString( GetVariableSystem.Exists('my_window_open'), 'gui.ClearWidgets my_custom_window', 'gui.createwidget gui/custom_windows/my_window.gui my_custom_window' ) )]" onclick = "[GetVariableSystem.Toggle('my_window_open')]" }
このトグルは、システム変数を設定し、その値に基づいて実行するコマンドを選択することで動作します。
Select_CString( ... )
は 3 つの引数を取ります:
- 条件
- 条件が true の場合の文字列
- 条件が false の場合の文字列
条件が true を返したら最初の文字列が使われ、そうでなければ 2 番目が使われます。 上記のトグルでは、システム変数が存在する場合はウィンドウを破棄し、存在しない場合は作成します。
既存のゲームビュー一覧[編集 | ソースを編集]
次の名前は、OpenGameView や IsGameViewOpen といったコマンドで使用できます。例: IsGameViewOpen('intrigue_window')
Game Views | ||
---|---|---|
intrigue_window | dynasty_house_view | artifact_kill_list |
military | dynasty_house_customization | action_item_handler |
men_at_arms | dynasty_tree_view | transfer_vassal |
knights | dynasty_legacy_window | title_election |
levy | dynasty_customization | court_window |
men_at_arms_type | dynasty_house_members | ruler_designer |
select_maa_origin_province | factions_window | royal_court |
army | succession_event | inventory |
holding_view | lineage_view | reforge_artifact |
character | religion | appoint_position |
character_finder | faith | artifact_details |
combat | faith_creation | language |
end_of_combat | faith_conversion | memories |
siege | culture_window | ruler_designer_save |
raid | hybridize_culture | ruler_designer_load |
rally_point | diverge_culture | activity_planner |
place_rally_point | add_culture_tradition | activity_window |
find_title | replace_culture_pillar | activity_list_window |
character_focus | great_holy_war | activity_list_detail_host_window |
lifestyle | hired_troop_detail_view | activity_list_detail_invite_window |
decisions | lease_out_baronies | activity_locale |
decision_detail | outliner | activity_guest_list |
title_view_window | my_realm | activity_intent_selection |
war_overview | succession_law_change | activity_log |
struggle | war_declared_overview | travel_planner |
struggle_involvement | war_results | travel_option_selection_window |
pause_menu | designate_heir | travel_route_edit_window |
load_game | change_ghw_target | accolade_view |
save_game | barbershop | create_accolade_view |
resign_confirmation | concubine_interaction | diarchy |
in_front_topbar | title_history | manage_tax_slots |
select_commander | title_add_law | tax_slot_appoint_tax_collector |
tutorial | title_customization | tax_slot_obligations |
council_window | kill_list | tax_slot_vassals |
tax_slot_assign_vassal |
トラブルシューティング[編集 | ソースを編集]
既知のクラッシュ理由[編集 | ソースを編集]
- hbox と vbox に 100% の size を設定する
- 同じ親要素で複数の子に
resizeparent = yes
を設定する
そのうち 1 つだけが可視でも、やはりクラッシュします
- 自己参照する型。RAM を使い切るまで無限のロード画面になります
- 構文エラー(波括弧や引用符の不足など)
ファイル内で {
を検索し、次に }
を検索して数を比較してください。数は一致しているはずです。
型のセットアップを再確認してください。型の構文は他の要素と異なります。
引用符の欠落については、エディタで正規表現検索を有効にし、= \[
と \]\n
を検索してください。通常、角括弧のまわりに引用符がない状態にはなりません。
便利なリンク[編集 | ソースを編集]
0 から 1 の正規化値を持つカラーピッカー。tintcolor などに便利です。
https://rgbcolorpicker.com/0-1
UI プロトタイピングに適したツール:
ドキュメンテーション | スクリプト • スコープ • 効果 • トリガー • 変数 • 補正リスト |
スクリプト | AI • ブックマーク • キャラクター • コマンド • 評議会 • 文化 • ディシジョン • 王朝 • イベント • 政府 • 歴史 • 領地 • ライフスタイル • 連隊 • 宗教 • スクリプト値 • ストーリーサイクル • 闘争 • 称号 • 特性 |
インターフェース | インターフェース • データ型 • ローカライズ • カスタムローカライズ • フレーバー化 |
マップ | マップ • 地形 |
グラフィック | 3Dモデル • エクスポーター • 紋章 • グラフィックアセット • フォント • パーティクル • シェーダー • ユニットモデル |
オーディオ | 音楽 • サウンド |
その他 | コンソールコマンド • チェックサム • Modの構造 • Mod制作ツール • トラブルシューティング |