投稿記事

ティラノスクリプトの記事 (5)

DSS 2020/09/15 00:00

[ティラノスクリプト]選択肢をキーボード操作で選びたいっ!

Javascript初心者が試行錯誤した結果ですが、ティラノスクリプト使ってる方で参考程度になればお使いください。

概要

ティラノスクリプトは基本の操作がマウスありきになっています。デフォルト設定だとキーボードでの入力は「スペース:メッセージの表示/非表示」、「Enter:次のメッセージに進む」、「Ctrl:メッセージをスキップ」くらいしか設定されていません。
キーボード操作をメインにしてるプレイヤーは選択肢が表示される度にマウスを持って選択肢を選んでクリックする必要があったりと、ゲームを進めるのに無精がしにくいのはプレイヤーとしては面倒だったりします。(主に私が。
スクリプトは少々面倒になりますが、キーボードでできることを増やすと先を急ぎたいプレイヤーとしてはありがたいものです(個人的な感想です。)!
今回はキー操作を強化することを試してみました。

やりたいこと

縦もしくは横に並んでいる選択肢が表示されている状態で上下矢印もしくは左右矢印で選択項目の変更、Enterキーで確定できるようにしたい。
何よりシナリオを書く時点で実装は楽にしたい!(あまり特別なオマジナイはしたくないっ!

前口上

data/system以下のキーコンフィグを使うやり方もあったのですが、今回は直接JavascriptでHTML要素にtabindexを追加して選択肢のフォーカスを切り換える方法にしました。ので、今回はキーコンフィグは使っていません。

あと、事前準備として、選択肢の各要素についてCSS上で:focusと:hoverの設定をできるだけ目立つようにしておいてください。
目立つようにしないと選択肢が選ばれているか視覚的に気付きません。

.selectLoop:focus, .selectLoop:hover {
border: solid 5px #ff9900;
border-radius: .5em;
margin: -5px
}

やり方

ソースは以下の通りです。

function keySet() {
	if($(".selectLoop").length>=1){
		//タブor矢印キーでフォーカス移動の選択肢
		$(".selectLoop").attr("tabindex","0");
		$(".selectLoop").first().addClass("loopFirst");
		$(".selectLoop").last().addClass("loopLast");
		$(".selectLoop").on("keydown", function(e){
			if(e.keyCode === 13) {
				$(this).trigger("click");
			}else if(e.keyCode === 38 || e.keyCode === 37 || (e.keyCode === 9 && e.shiftKey)){
				//↑、←、Shift+tabキーのいずれかの処理
				if($(":focus").hasClass("loopFirst")){
					//最初の選択肢だったら、最後にループ
					event.preventDefault();
					$(".loopLast").focus();
				}else if(e.keyCode === 38 || e.keyCode === 37){
					$(":focus").prev().focus();
				}
			}else if(e.keyCode === 40 || e.keyCode === 39 || (e.keyCode === 9 && !e.shiftKey)) {
				//↓、→、tabキーいずれかの処理
				if($(":focus").hasClass("loopLast")){
					//最後の選択肢だったら、最初にループ
					event.preventDefault();
					$(".loopFirst").focus();
				}else if(e.keyCode === 40 || e.keyCode === 39){
					$(":focus").next().focus();
				}
			}
		});
		$(".selectLoop").on("mouseenter", function() {
			$(this).trigger("focus");
		});
		$(".selectLoop").first().focus();
	}
}

いつも通りですがマクロ化しておくと便利です。

[macro name="keySet"]
	[iscript]
		keySet();
	[endscript]
[endmacro]

このスクリプトのポイントは以下の通りです。

  • キー操作対象は[glink][button]両方で利用できるようにしたい。([link]は使うつもりもないので、対象外にしています。
  • キーの操作対象は画面上のすべての選択肢ではなく、都度設定できるようにしたい。(キーボード操作の対象となる選択肢は物語の進行に関連したものだけにしたいため。Fixed buttonとかは選択肢のループに入ってこないでっ!
  • 画面に選択肢が表示されたら、第一候補が自動的に選択されている状態にしたい。しかも選択の変更は矢印キーで操作できるようにしたい!(え?tabキーでもできちゃうの?なら、それでも同じように動いてほしいわ。

使い方

1) ティラノスクリプトのdata/othersに新しいフォルダを作り、その中に新しいjsファイルを作成する。 例)data/others/original/test.jsなど
2) テキストエディタなどでtest.jsを開き、先述のコードを追記。保存して閉じてください。
3) data/scenario/first.ksに以下のタグを追記。
 必ずタイトル画面など別のksファイルにジャンプする前に実行できるところに記述してください。(ついでに先述のマクロの定義も下記のタグの直下に追加しちゃいましょう。

; 外部JSの読み込み(./data/others/original/test.js)
[loadjs storage='original/test.js']

4) あとはシナリオファイルを記述する中で、[glink][button]を使った選択肢を記述するときにname="selectLoop"をタグ内に追加して、選択肢の記述の直後に先ほど定義したマクロ[keySet]を記述すれば対象の選択肢が自動的にキーボード操作対象になります。

以上です!ラクチンですね。それなりに汎用性あると思うので結構満足。(イベントハンドラで選択肢以外の要素を汚すことないし。

既存の不具合というか未解決課題

残念ながら完全無欠の仕様にはなっていません。

  • マウスで画面の違うところをクリックすると、フォーカスがずれてキー入力を受け付けてくれなくなってしまいます。tabキーを一度押すか、マウスをオーバーラップすると戻ってくるんですけど、この機能ってどうやったらエミュレートできるんだろう?
  • Fixed buttonが混ざるとそれにはフォーカスがうまく移動しません。具体例としては、ティラノスクリプトのダウンロードした時に起動できるサンプルゲームのタイトル画面。「はじめから」「CGモード」「回想モード」はフォーカスしますが、roleで指定してFixed buttonになっている「つづきから」「コンフィグ」にはフォーカスが移動しません。一旦Fixed buttonにならないように通常buttonとして配置して、target先にてrole対象へジャンプする処理をすることで回避できます。

解説

では、一つずつ解説です。
前提として、[glink][button]はどちらもnameパラメータを持っており、ゲーム画面描画の時に対象のhtml要素のclassにnameで設定した文字列が記述されるのがティラノスクリプトの仕様です。なので、「[glink][button]で利用可能にすること」と、「都度対象の選択肢を設定できるようにすること」は、class名を利用して解決しました。
javascriptの処理の方ですが、$(".selectLoop")で、先ほどname="selectLoop"に設定した選択肢すべてを取得しています。

  • Tabキーを押したり矢印キーで選択肢を順番に移動できるようにする機能自体はtabindexの機能を用いています。そのため、対象になる要素にtabindex=0を一律で設定しています。
$(".selectLoop").attr("tabindex","0");
  • そのままでは最初と最後の選択肢でループしないので、そのための事前準備をします。それぞれの要素に最初と最後が分かるように新しいclass名を追加します。
$(".selectLoop").first().addClass("loopFirst");
$(".selectLoop").last().addClass("loopLast");
  • この行以降は各要素にキーが押されたときの動作を登録していきます。
$(".selectLoop").on("keydown", function(e){
  • Enterキーが押されたときにフォーカスされている選択肢がクリックされたと認識させます。
$(".selectLoop").on("keydown", function(e) {
	if(e.keyCode === 13) $(this).trigger("click");
 });
  • ↑、←、Shift+tabキーのいずれかが押されたときの処理を記述します。まず現在フォーカスされている要素を取得して。それが最初の選択肢であれば最後の選択肢にループするようにします。event.preventDefault();はShift+tabキーを押したときに自動で一つ戻ってしまう動作をキャンセルするコマンドです。これをしないと選択肢が一つ飛んでしまいます。次にそれ以外の選択肢だった場合かつ↑、←キーだったときは一つ前の選択肢にフォーカスを移動させます。Shift+tabキーはデフォルトの機能として一つ前の選択肢にフォーカスを移動させてくれます。
			}else if(e.keyCode === 38 || e.keyCode === 37 || (e.keyCode === 9 && e.shiftKey)){
				//↑、←、Shift+tabキーのいずれかの処理
				if($(":focus").hasClass("loopFirst")){
					//最初の選択肢だったら、最後にループ
					event.preventDefault();
					$(".loopLast").focus();
				}else if(e.keyCode === 38 || e.keyCode === 37){
					$(":focus").prev().focus();
				}

続いて}else if(e.keyCode === 40 || e.keyCode === 39 || (e.keyCode === 9 && !e.shiftKey)) {以降は↓、→、tabキー用の処理です。基本的には次の選択肢にフォーカスを移す処理になります。

  • 上記のままではマウスが他の選択肢上に移動してもフォーカスが自動で変わらないので、マウスが他の選択肢上に移動したら、フォーカスも移動させます。
$(".selectLoop").on("mouseenter", function() {
	$(this).trigger("focus");
});
  • そして最後に一番最初の選択肢があらかじめフォーカスされた状態を設定します。
$(".selectLoop").first().focus();

とりあえず現時点では以上です。もしかすると既存の課題が今後クリアにできれば、また追記したいと思います。

DSS 2020/09/14 16:57

[ティラノスクリプト]ロード後の不具合とかメモ

私がやってちょっと引っかかったことのメモ。

ロード後に発生した面倒ごと

  • [anim layer="0" その他パラメータ]で画像が移動しない!?
    →同じレイヤーに再描画されるみたいだけど、タグでアニメーションとかできなくなるみたい。仕方がないので[freeimage layer="0"]でレイヤー内の画像を全削除して、再描画するしかなかった。ロードの時に再描画できるようにサブルーチンかマクロを準備してmake.ksに呼び出しを記述。マクロはそのまま書けば良いけど、サブルーチンなら、callして戻ってくるようにしないとおかしくなります。jumpは使っちゃダメ!

  • 外部jsからティラノスクリプト内の関数が読めなくなる!?
    tyrano.plugin.kag.stat.f[name]TYRANO.kag.stat.f[name]はロード前は同じように値を返してくれるけど、ロードをすると挙動が変わるみたい。tyrano.plugin.kag.stat.f[name]はロード後値が参照できなくなるけど、TYRANO.kag.stat.f[name]の方はロード後も変わりない。使うならTYRANO.kag.stat.f[name]の方が安全っぽい。

また何かあったら追記します。

DSS 2020/09/14 16:46

[ティラノスクリプト]オリジナル関数を導入したい場合(初心者向け)

私自体がJavascript初心者なので、偉そうなことは何も言えないのと、内容として間違ったことを言っているかもしれません。
ということを承知の上で、私がやってみて上手く言った手順を書いておきます。

やりたいこと

ティラノスクリプトのタグでは実装が難しい処理を直接Javascriptで記述する(オリジナルの関数を作る)。それをプロジェクトのどこからでも使えるようにする。

やり方

1) ティラノスクリプトのdata/othersに新しいフォルダを作り、その中に新しいjsファイルを作成する。 例)data/others/original/test.jsなど
2) テキストエディタなどでtest.jsを開き、コードを追記。保存して閉じてください。

function 関数名(必要あれば引数){ //例:testFunc(hoge)
	処理内容
    return 必要あれば返値;
}

3) data/scenario/first.ksに以下のタグを追記。
 必ずタイトル画面など別のksファイルにジャンプする前に実行できるところに記述してください。

; 外部JSの読み込み(./data/others/original/test.js)
[loadjs storage='original/test.js']

[macro name="マクロの名前(例:testMacro)"]
[iscript]
testFunc(mp.value);
[endscript]
[endmacro]

4) あとは必要な所で[testMacro value="設定値"]やiscript内でtestFunc(hoge);と記載するだけで利用できるようになります。

外部jsで知ってないと時間をムダにしちゃうこと

  • ティラノスクリプト内のf.name変数の読み書き
TYRANO.kag.stat.f[name]
  • ティラノスクリプト内のtf.name変数の読み書き
TYRANO.kag.variable.tf[name]
  • ティラノスクリプト内のsf.name変数の読み書き
TYRANO.kag.variable.sf[name]
  • ティラノスクリプトのタグの実行
TYRANO.kag.ftag.startTag("タグ名", {パラメータ1:"値1",パラメータ2:"値2"});

 パラメータと値のセットは必要な分だけ追記していきましょう。一つもなければ{}にすればOK。

そもそも何で外部jsに記述するの?

プロジェクトのどこからでも再利用可能にするならiscriptタグを内包したマクロやcallでサブルーチンを呼び出しても良いです。
が、たまにiscriptタグ内に書くと上手く動かないことが出てきました。
具体的にはプラグインで使われている変数の書き換えなど。無理やり書き換えたい対象がいるけど、ティラノスクリプト外の変数(f.~、tf.~、ts.~とか以外の変数)だとiscriptから書き換えるには何かテクニックがいるのか、上手くできませんでした。
また、オリジナル関数を定義する場合もiscript内で定義してはいけません。そのiscriptの中でしか使えないみたいなので、別途マクロやcallとして対象のiscript自体を呼び出さなくてはいけなくなります。
引数が多い関数とかの場合はマクロとかでは記載が面倒になるので、直接オリジナル関数を使ってしまいたい場合も出てくると思います。

いずれもJavascriptの「スコープ」問題だと思っています。興味のある方は一度ググってみてください。

DSS 2020/09/14 07:54

[ティラノスクリプト]ロードするとtyrano.plugin.kag参照できないよっ!

そういえば、この前ハマったんですけど、外部jsでtyrano.plugin.kagで記述したんですけど、ロードすると値が参照できなくなっちゃうんですよね。

偶然他のサイト様を見つけたのですが、やはりロードを挟むとtyrano.plugin.kagでは値が参照できなくなるようです。
で、TYRANOオブジェクトを代わりに使うと解決するらしい。
そちらのサイト様では、「とりあえずTYRANOの方を使っておいた方が無難な気がする」そうです。
確かにこれでなら、私も問題は解決できるっぽいですが、もうティラノスクリプトのタグでなんとか置き換える方法を見つけてしまったので、また次の機会に利用してみます。

DSS 2020/09/14 07:16

[ティラノスクリプト][Live2D]表示レイヤーの変更方法

ティラノスクリプトをベースにLive2Dプラグイン(Cubism3.x系)を導入する場合にモデルの表示レイヤーを変更するための方法です。
同じくティラノスクリプトとLive2Dでゲームを作ってる人がいれば使ってください。

「ティラノスクリプトfor Windowsアプリケーションv475b」と「live2d_tyrano_plugin_v304 プラグイン(2020/1/11)」の組み合わせで思惑通りに動作しました。
ただ、私もプログラミングは専門外なので、ご利用の際は自己責任でお願いします。
Live2Dの利用規約には反してないはずなので、このやり方でも怒られたりはしないと思うけど。。。

概要

ティラノスクリプト上でLive2Dを導入する場合、公式のプラグインで簡単に導入できますが、モデルの表示はレイヤー0に固定表示となります。
重なり方をカスタマイズしたい場合やゲーム制作の都合でLive2Dのモデルをレイヤー0以外に指定したい場合、以下の方法を試すことで解決できるかと思います。

利点

Live2Dのモデルをプラグイン無改造で別レイヤーに表示できるため、animタグなどでレイヤーごとの移動や配置するレイヤーを分けることで表示の管理、演出が楽にできるようになります。

やり方

※ティラノスクリプトへLive2Dプラグインの導入は済ませておいてください。
1) ティラノスクリプトのdata/othersに新しいフォルダを作り、その中に新しいjsファイルを作成する。 例)data/others/original/test.jsなど
2) テキストエディタなどでtest.jsを開き、以下のコードを追記。保存して閉じてください。

function live2dlayer(layer){
	_live2d_tyrano = {
	    "layer":layer
	};
}

3) data/scenario/first.ksに以下のタグを追記。
 必ずタイトル画面など別のksファイルにジャンプする前に実行できるところに記述してください。

; 外部JSの読み込み(./data/others/original/test.js)
[loadjs storage='original/test.js']

4) シナリオファイル中でLive2Dのモデル読み込み[live2d_new]する直前に以下の処理を挿入してください。

[iscript]
live2dlayer("表示させたいレイヤー 例:0");
[endscript]

以上の処理で任意の前景レイヤーにLive2Dモデルを表示できるようになるはずです。

補足説明

・複数のLive2Dモデルを表示する場合、標準プラグインは一つのCanvasにそれらのモデルを追加する仕様のため、別々のレイヤーに個別にモデルを配置することはできません。
・別レイヤーにLive2Dの表示を変更したい場合は一度[live2d_delete_all]でLive2Dのモデルをすべて削除してください。
・手順4の記載内容はfirst.ksなどでtest.jsを読み込んだ直後にマクロとして宣言しておくと便利だと思います。その場合は以下を記載してください。

[macro name="マクロの名前(例:l2dLayer)"]
[iscript]
live2dlayer(mp.layer);
[endscript]
[endmacro]

以降は[l2dLayer layer="1"]と記載すれば前景レイヤー1にモデルが表示されます。


てか、ぶっちゃけlive2dtyrano.jsの64行目あたりでpmにlayerパラメータ追加して、84行目のvar layer = _live2d_tyrano.layer;の前で指定があれば_live2d_tyrano.layerを書き換えればダイレクトに[live2d_new]にlayerパラメータ指定できるのに何で公式やらないのかなぁ?何か問題あるんだろうか??あれかな、モデルごとには別々のレイヤーが設定できないから、導入してないとか?う~ん。。。


z-indexを試して上手くいかないと困っている方は無料プランにその原因と上記手法を導入した経緯を記載しました。
知りたい人だけどうぞ。(読む必要性はあまりないと思いますが。)

フォロワー以上限定無料

どなたでも無料で支援が出来ます。

無料

記事のタグから探す

月別アーカイブ

限定特典から探す

記事を検索