『RPGツクールMZ』で文字列・配列を使う
と JavaScript の入門的なやつを三本書いたわけですが、今回も一応入門の続きということで値について書きます。
ただ、半分ぐらいはもう入門じゃないなって感じもします。
主に[変数の操作]-[スクリプト]で使うことを想定していますが、他のコマンドでの使い方もちょこちょこ出てきます。
プラグインでの使い方は説明しません。
公式のプラグイン入門だと最速JavaScript講座:変数のあたりですね。
そろそろ、JavaScriptそのものをまともに勉強したいという人もいると思うので、入門サイトを並べておきます。
お好きなやつをどーぞ。
- ドットインストール
- progate
- ハーバード大学 JavaScript Lecture 5 CS50's Web Programming with Python and JavaScript 2020(日本語字幕付)
用語
今回はこれまで次のようにざっと書いていた用語を詳細に解説する感じです。
配列…値に番号をつけて並べた値。例:[ 10, 4, 6 ]
(これは値として数字を並べていますが他の値も並べられます)
添字…「そえじ」配列(を保持している変数)から値を取り出す際に使う数字。例:array[ 0 ]
( JavaScript の配列の添字は 0 から始まります)
文字列…文字を並べた値です。JavaScript 的には String
です。値が文字1つに固定された配列と考えてもいいです。例: "文字列でーす"
真偽値…真(正・ON)と偽(負・OFF)の2つを取る値です。JavaScript 的には Boolean
で2つの値は true
と false
で表されます。
論理演算…計算の結果として真偽値を返す演算です。値の多少を判定する条件式などが含まれます。
変数…値を保持しています。JavaScript の変数も『RPGツクールMZ』の[変数]とだいたい同じです。定義例:let variable;
以前は定義に let
ではなく var
を使っていましたが問題が多く、今(2022年現在)はあまり使われていません。逆に var
が使われていると素人でも簡単に古いコードだと分かります。なお『RPGツクールMZ』になってコアスクリプトは var
を廃止してます。
定数…変数とだいたい同じですが、一度値を設定したら変更できません。一見不便に感じますが、実は変数より便利で、実際のプログラミングでは、ほとんど変数を使う必要はありません。定義例:const constant = 1;
若干うるさいですが以下、『RPGツクールMZ』の[変数]は角カッコつきで書いて JavaScript の変数はそのまま書くことで区別します。
文字列
文字列…文字を並べた値です。JavaScript 的には String
です。値が文字1つに固定された配列と考えてもいいです。例: "文字列でーす"
と、雑に説明してきましたが、ここでもうちょっと詳しく説明しようと思います。
一番簡単かつ有用な[スクリプト]はおそらく、[変数の操作]の[スクリプト]を使って文字列を[変数]に入れることかと思います。
次のように "
でくくるだけで簡単に文字列を[変数]に代入できます。
"クォートして文字列を書けばいいんだよ";
そして、[文章の表示]で \v[1]
という感じで書けば、そのまま文字列が表示できます。
これを使えば、かなり細かくセリフのバリエーションが作れます。
もうこのページで伝えたいことはほぼ伝えました(笑)
文字列の条件判定
条件判定で[変数]を条件に入れることができますが、文字列との比較は用意されていません。
これではあまり役に立たないのでは?と思われるかもしれませんが、いろいろ方法はあります。
まず、[変数]との比較はあるので、一時[変数]に文字列を代入して比較するという手があります。
[実行内容]だとこんな感じ。
◆変数の操作:#0003 = "判定文字列"
◆変数の操作:#0004 = "条件文字列"
◆条件分岐:#0003 = #0004
◆文章:なし, なし, ウィンドウ, 下
: :\v[3] と \v[4] は同じ!
◆
:それ以外のとき
◆文章:なし, なし, ウィンドウ, 下
: :\v[3] と \v[4] は違う!
◆
:分岐終了
もうひとつは[条件判定]で[スクリプト]を使って判定する方法です。
$gameVariables.value( 3 ) === "条件文字列";
[実行内容]だとこんな感じ。
◆変数の操作:#0003 = "判定文字列"
◆条件分岐:スクリプト:$gameVariables.value( 3 ) === "条件文字列";
◆文章:なし, なし, ウィンドウ, 下
: :\v[3] と 条件文字列 は同じ!
◆
:それ以外のとき
◆文章:なし, なし, ウィンドウ, 下
: :\v[3] と 条件文字列 は違う!
◆
:分岐終了
JavaScript で判定すると、「ではない」場合の判定も簡単です。
$gameVariables.value( 3 ) !== "条件文字列";
厳密等価演算子
===
と、何でイコールを3文字も並べなきゃいけないのか謎ですよね。
実は ==
の2文字でも判定されます。
ただ、次の判定が右と左で数値と文字列なのに真( true
)になるのです。
2 == "2"
JavaScript の基本方針として「テキトーに書いてもテキトーに判断して実行する(大意)」というものがあったため作られた仕様だと思います。
結局それはどういった場合にどんな挙動をするのか、すべて知らないと使えない、という初心者に優しいものとは逆のものになっています。
おや?なんかツクールで体験したような気もしますね…。
それはそうと ===
の場合は以下の結果は false
です。
2 === "2"
使い分けようとすると間違いが起こりがちなので、比較は ===
と書く!と決めてかかった方が良いです。
もし、文字列を数値として比較したいならば、明示的に(スクリプトとして見える形で)文字列を数字に変換して、たとえば次のように書くべきです。
2 === Number( "2" );
左右が等しいことを判定する等価演算子は、そもそも ===
とか ==
じゃなくて =
でよくなかったのか?という疑問もあると思います。
数学と違う記号使うのってわかりにくいですしね。
でも代入演算子を =
にしちゃったんで、等価演算子に =
を使えなくなっちゃったんですよね、間抜けな話です。
ちなみに ALGOL など :=
で代入するものや、AppleScript のように set a to "B"
という式による代入のプログラミング言語もあります。
しかし主要なプログラミング言語の代入演算子が =
であるため、もうひっくり返すことができなさそうです。
実際、初期は :=
だった B言語も =
に変わってしまいました。もうみんな =
に慣れすぎて、変えるとバグを産んでしまうという状況になっているのです。
皆さんも諦めて =
を代入演算子として受け入れましょう(とほほー)
蛇足っぽいですが「子(し)」ってつく言葉はコンピュータ用語によく登場しますが、これは「何かを行うもの」ぐらいの意味です。
編集子(へんしゅうし)とか見たことないですか?編集者とだいたい同じ意味ですが、ちょっと匿名性が高い言葉です。
というわけで「子(し)」は何かの子供でもネズミでもないくて英語の「-er」に相当する言葉なのです。
つまりドラゴンスレイヤーを訳すと竜討伐子になり、デーモンスレイヤーを訳すと竈門禰豆子となるわけです(笑)
文字列の結合
文字列同士をつなげるには +
記号を使います。
[スクリプト]に書く場合はこんな感じです。
const result = "前の文字列" + "後ろの文字列";
ただ[スクリプト]の場合は[変数]を扱うの面倒臭いですよね。
実は[変数の操作]で[操作]-[加算]を選んで[オペランド]-[スクリプト]に文字列を書けば、[変数]に文字列を追加して[変数]に戻す操作ができます。
また[オペランド]-[変数]で[変数]に文字列が入っていれば、同様に追加して[変数]に戻す操作ができます。
暗黙の型変換
片方が文字列、もう片方が数値の場合は、JavaScript は数値を文字列として結合します。
"123" + 4; // 結果は文字列 "1234"
つまり、数値を暗黙に(スクリプトとして見えない形で)文字列に変換しています。
掛け算の場合はどうでしょう。エラーが出そうですね。
"123" * 4; // 結果は数値 492
なんと…今度は文字列を暗黙に数値に変換しています。
これ一見便利な感じもしますが、結局すべてのパターンでどういう挙動をするか覚えておく必要があって、まったく便利じゃありません!
掛け算で数値として扱われたなら、足し算でも数値として扱われると思うのが普通だと思います。
『RPGツクールMZ』も一見便利だけど、その挙動を把握しておかないと使い物にならないというヘッポコぶりが似てますね!
たとえばオートタイルとかも、不便の方に傾いてる気がします!!
というわけで、文字列を数値として扱う場合 Number()
などを使って明示的に(スクリプトとして見える形で)数値に変換してから使うのがいいでしょう。
なお、明示的に文字列として結合するには concat()
メソッドを使います。
"123".concat( 4 ); // 結果は文字列 "1234"
が、あんまり使われてません +
のほうが圧倒的に速いんですよね…。
バッククォート `
と ${}
を使えば、文字列の中に埋め込むような書き方もできます。
const n =100;
const result = `お釣りは ${ n }円`;
バッククォートは改行を含む複数行に対応しているので、とくに長い文字列の場合、非常にみやすく書けます。
しかし、ただでさえ狭い[スクリプト]に長い文字列を書くことはないですから、サンプルにバッククォートが使われていた時にびっくりしない、程度になっておけばいいと思います。
バッククォートを使った書き方、続きはMDNへ!
豆知識
ところでオペランドってなんでしょうか?『ラ・ラ・ランド』みたいなミュージカル?
さにあらず。さにあらず。
オペランドとはプログラミング用語で「操作の対象となるデータ」を意味する言葉です。
…「値」とか「データ」で良かったのでは?
ちなみに操作の方はオペコードと言います…なぜオペランドだけ採用したのかも謎です。
Operand (オペランド) - MDN
長年プログラミングをやっていたとしても、(現場によるでしょうけど)オペランドって言葉を使うことは稀です。
<Bad!>それをなんで「プログラミングができなくてもゲームが作れる」でおなじみのツクールの用語に採用したのか!?
文字列から1文字を使う
実は文字列は位置指定が簡単にできるので、1つの[変数]で多くの判定ができたりします。
[変数]ID1に入っている4番目の文字次の通りです。
$gameVariables.value( 1 )[ 3 ] === "字";
番号は 0 から始まるので、4文字目を指定する場合は 3 になるので注意してください。
最初の丸カッコ ( )
はメソッドを実行するためのカッコで、次の角カッコ [ ]
はメソッドの返り値である文字列に添字を書くためのカッコです。
なので、次のように分解できます。
const string = $gameVariables.value( 1 );
string[ 3 ] === "字";
この程度なら分解するほどでもないですが、分解方法がわかってると何かと応用が利きます。
文字が存在しない場所を指定すると undefined
という特別な値が返ってきます。
「定義されていない」という意味です。
それと文字列を比較すると必ず false
になります。
また文字列なので JavaScript が最初から持っているメソッドを利用でき、とくに正規表現を活用すると複雑な処理が可能です。
そこ説明するとこのページの記述量どころではなくなるので、みんな大好きMDNをご覧ください。
正規表現
もしかしたら今まで『RPGツクールMZ』や JavaScript 関連の情報を調べているときに、正規表現の文字をチラッと目にしたことがあるかもしれません。
実際エディタで[検索]を選ぶと検索ダイアログの下の方[一致]の中に[正規表現]の文字があります。
ヘルプを見ると…正規表現どころか部分一致の説明すらないですね。
<Bad!>書いとけよ!!
正規表現は文字列の検索(パターンマッチ)を行うために作られた記号体系です。
JavaScript 以外のプログラミング言語はもちろん、テキストエディタ…そして先ほど書いたように我らが『RPGツクールMZ』でも使われる汎用的な仕組みです。
(基本的な書式は一緒なんですが、微妙に環境によって違いがあるのが困ったところ)
次のスクリプトの r.+
という部分が正規表現で「r から始まり、その後ろに空白でない文字が1つ以上続いている」という意味になります。
これだけの情報を r.+
という短い文字列に込めているのですから、正規表現の便利さがもうわかってきたと思います。
"This is a regular expression!".search( /r.+/ );
"This is a regular expression!"
という文字列に対して search()
というメソッドを実行し引数に正規表現オブジェクトを渡しています。
結果は 10 、これが正規表現で指定した文字列が存在する位置です。
見ての通り正規表現オブジェクトは /
で囲うことで生成できます。文字列が "
や '
あるいは `
であったのと似た感じです。
極めて柔軟な処理が可能なので、学習意欲旺盛な方はぜひ正規表現を覚えて活用してください。
正規表現をちゃんと覚えるには新たにプログラミング言語を覚えるぐらいのコストがかかるんで、最初はちょっとだけの感じで取り組むといいでしょう。
ちなみに私も、それほどきちんと正規表現を身につけているわけでもありません。
おおっと、気づいてしまいましたね。毎度恒例 MDN に丸投げです!
多数の値を一度に使うには?
文字列中の1文字をスイッチに見立てれば、1つの[変数]で大量のスイッチを管理できる。
そう思った方もいるかもしれません。実際できはします。
直感的には次のように書けば入れ替えられそうです。
$gameVariables.value( 1 )[ 3 ] = "変";
先ほど出てきたスクリプトの比較演算子を代入演算子に変えたものです。
[ ]
で文字列の1つを取り出すことはできても、入れ替えるのはこの方法では無理なんですよね。
以下、入れ替えスクリプトの例です。
const str = $gameVariables.value( 1 );
const result = str.substring( 0 , 3 ) + "変" + str.substring( 4 );
$gameVariables.setValue( 1, result );
ご覧の通り、面倒臭いのでオススメしません!
数値の桁を活用しても複数のスイッチを扱えるのでは?と思った方もいるかもしれません。
鋭いです。JavaScript は二進数も扱えビット演算が可能です。
フラグ管理だったら、文字列を使うより簡単ですね!(ボブの絵画教室のような笑顔で)
…勘の鋭いあなた、そうです、ボブみたいにはいきません!!
そういう多数の値をまとめて使うための値として、JavaScript には「配列」というのものが用意されています。
ビット演算
さて話の流れで出てきたビット演算、ちょっと気になりますか?
コンピュータで使われる数字は二進数を基本とするという話を聞いたことがあるかもしれません、だいたい「二進数 = ビット」と思っていいです。
つまりビット演算とは「二進数に対する計算」ということで、JavaScript はそのための仕組みも持っています。
二進数は頭に 0b
をつけて表します。
0b10000;
結果は 16 です。この結果で JavaScript では普通の数値と同じ十進数として扱われるのがわかります。
え、二進数がわからない?ニシンそばならわかる?インターネット検索はあなたの友達です!
さて、ビット演算ですが二進数を扱うのに便利な演算で、たとえば &
演算子は両辺共に1の桁以外は0にします。
0b11111 & 0b10000;
結果は 16 です。つまりビットが立っている(1である)桁の状態だけを取り出せるわけです。
どの桁が残っているのであれ JavaScript では 0
は false
、0
以外の数値は true
判定されます。
これを利用すれば前述の「ひとつの数値の中にスイッチをたくさん」が実現できるじゃあぁりませんかっ!!!
…面倒臭い?昔はみんなこれでフラグ管理してたんじゃ!貴様らもやるのじゃ!!(老害発言)
というわけで、お待たせしました、MDNです!
ビットでフラグを扱うのは悪しき習慣とまで言われてますね…。
『RPGツクールMZ』ではマップデータのタイル属性がビットで扱われてますが、直接扱わなくても分解した状態で取り出せるメソッドがあります。
というわけでの[スクリプト]でビット演算を行う機会は、ほぼないと思います。
トーリービアー♪
そして気づいてしまった人もいるかもしれません。ビット演算子に &
を使ってしまったので論理演算子に &&
を使わざるを得なくなったことに…。
JavaScript は C言語系なので、C言語の責任と言えそうですがC言語が使われる領域ではビット演算を多用するので、そんなにおかしな判断ではないんですよね。
人に歴史ありというか、プログラミング言語もいろいろな紆余曲折があって現在の仕様が決まってて、一見変なものもあるのですが、なかなか使用策定時点では予測できないことがあります。
JavaScript の場合はテキトーにC言語の仕様を引っ張ってきて突貫で策定しちゃったのに、まさかこんなに広く使われるようになるとは思わなかった、という感じだと思います。
なので JavaScript の仕様って現状に合ってなかったりしますが、予測は誰にもできないので咎めないようにしましょう。
個人的には「このクソ仕様が!!!」と心の中で罵るのに止めておきます(ダダ漏れでは?)
配列
配列…値に番号をつけて並べた値。例:[ 10, 4, 6 ]
(これは値として数字を並べていますが他の値も並べられます)
と雑に説明してきた配列ですが、もうちょっと詳しく説明します。
JavaScript では Array
というクラスで…MDN!MDN!
え、早い?
配列も文字列と同様に[変数の操作]の[スクリプト]を使って[変数]に入れることができます。
次のように []
でくくって値を順に書いていけばOK。
[ 10, 4, 6 ];
そして、[文章の表示]で \v[1]
という感じで書けば、,
区切りで値が結合されて表示されます…が。
文字列に比べるとそのままで使うことは、まずないでしょう。
じゃあどう使うのか、詳細を見ていきましょう。
配列の取得
さて、[変数]に値を入れることはできましたが、取り出す場合はどうするのでしょう。
[変数の操作]の[スクリプト]に次のように書けば、[変数]ID1に入れた配列の4番目の値を取り出せます。
$gameVariables.value( 1 )[ 3 ];
配列の各要素には数値以外の値も入れられるので、文字列を使ってみます。
[ "リード", 15, "♂" ];//[変数]ID1に代入
そして[変数の操作]で取り出すときに結合してみましょう。
[変数]を[単独]の2
に設定、[操作]を代入
に設定、[オペランド]の[スクリプト]に次のように書きます。
const a = $gameVariables.value( 1 ); "彼は" + a[ 0 ] + "、" + a[ 1 ] + "才 " + a[ 2 ]; //[変数]ID2に代入
そして[文章の表示]で \v[2]
を使えば表示できます。
彼はリード、15才 ♂
と出るはずです。
コピペしなかった人はエラー出してるかもしれませんが…コピペしましょうね!
たまに間違ったスクリプトが書かれてることもありますけど…いや、公開前にテストはしてるんですよ!でも、なんか間違うんですよ!!
さて、先ほどのスクリプトは一度定数 a
に入れているので、後が簡単ですね。もし定数に入れずに書くとこんな感じになります。
"彼は" + $gameVariables.value( 1 )[ 0 ] + "、" + $gameVariables.value( 1 )[ 1 ] + "才 " + $gameVariables.value( 1 )[ 2 ]; //[変数]ID2に代入
ちなみにバッククォートを使った書き方だとこうです。
const a = $gameVariables.value( 1 ); `彼は${ a[ 0 ] }、${ a[ 1 ] }才 ${ a[ 2 ] }`; //[変数]ID2に代入
[変数]を3つ使っていたのが1つですむようになって便利!と思えるかというと、若干微妙かもしれません 。
[変数]の階層構造が使えると考えれば、ファイルベタ置きよりフォルダで整理してある方が使いやすいのは自明だと思います。
配列の要素への代入
そして[変数の操作]で配列の各要素に代入できると便利なんですが、そこは無理です。
なので[スクリプト]を使い、先ほどの[変数]ID1のデータの番号1の要素に代入します。
$gameVariables.value( 1 )[ 1 ] = 10;
文字列では取り出すことはできても、設定はできませんでしたから、配列は高性能です!
見ての通り、割と簡単に書けます。
彼はリード、10才 ♂
と、1番の要素が 15
から 10
に変わりました。
ちなみに分解すると、こんな感じ。
const a = $gameVariables.value( 1 );
a[ 1 ] = 10;
この方法では[変数]の値を書き換えても[イベント]の走査がされず、[出現条件]によって[EVページ]が変更されることはありません。
ただ、もともと[出現条件]に配列の値を設定することはできませんから、とくに問題はないと思います。
イベントコマンドのスイッチ・変数と配列
実のところ『RPGツクールMZ』の[スイッチ]や[変数]は配列です。
番号が振ってあって、番号に対応した値が保存されています。
これは概念的な話だけではなく、実際コアスクリプトは JavaScript の配列として[スイッチ]や[変数]を保持しています。
$gameVariables._data; // これ配列です!
つまり添字をつけて値を指定できます。
$gameVariables._data[ 1 ];
これだけだと、普通に[変数の操作]でやったほうが簡単なんですけど。
先ほどもやったように、配列は文字列と違って添字で指定した値に対して代入もできます。
$gameVariables._data[ 1 ] = 10;
ここで気になるのは、次のスクリプトとどう違うのかということです。
$gameVariables.setVariable( 1, 10 );
基本的には一緒なんですが、setVariable()
の場合は設定した数値の小数点が切り捨てられることと、設定した後に[イベント]の条件が走査されて変更した[変数]によって[EVページ]の切り替えが行われることが違います。
これは[変数の操作]によって[変数]を変更した場合と同じ挙動です。
逆に上の _data
配列に直接代入する場合、小数点以下も設定でき、[イベント]の条件は走査されません(有り体に言うと処理が速いです)
[変数の操作]以外でもメソッドを通す場合と通さない場合に両方の操作があることは珍しくないですが、大抵は両者に違いがなかったりします。
しかし、このsetVariable()
と _data
の場合のように挙動に違いがある場合もあります。
基本的にメソッドを使ったほうが[イベントコマンド]での挙動に近いので、メソッドを使っていくのが良いでしょう。
メソッドと配列
ついこのように書いてしまいそうになりますが、これはできません。
$gameVariables.value( 1 ) = 10;
()
はメソッドに引数を渡すための記号で、配列の要素を取り出しているわけではないからです。
じゃあ、配列の添字としてこう書けばいいと思うかもしれません。
$gameVariables.value[ 1 ] = 10;
非常に考え方はいい感じのところまで行っているんですが、これもできません。
value
が配列ではないからです。 _data
の方が配列でしたね。
どれがメソッドでどれが配列(Array)なのかはコアスクリプトを見る必要があります。
それはなかなかヘビーなので『RPGツクールMZ 非公式JavaScriptリファレンス』で確認してみるといいでしょう。
ところで、先ほど出てきたスクリプト。
$gameVariables.value( 1 )[ 1 ] = 10;
ということは、これもいけるのでは?と考えた人もいるかもしれません。
$gameVariables._data[ 1 ][ 1 ] = 10;
そんな疑問が出たら、バンバン試してみましょう!
大抵うまくいきませんが、うまくいくとなんとも言えない達成感かあります。ゲームで謎解きに成功した感じの!
探索・推理系のゲーム好きであるツクラーは、こういう意味ではプログラマ向きです。
プログラミングも、趣味として楽しんでいきましょう!!
文字列と数値の変換
文字列と数字を互いに入れ替える方法は色々ありますが、プログラミング言語でも一般的(と思います多分)な、クラス名にカッコをつける方法を推しておきます。
型変換のことをキャスト(type casting)と言ったりします。型変換でいいだろって思いますが、キャストはよく使われますので一応。
また、他の方法もそこそこの頻度で目にすると思うので、見たときに「ナンジャコリャ?」とならないように一応並べておきます。
文字列から数値へ
推奨。
Number( "2" );
裏技っぽい方法。
1 * "2";
文字列に余計な文字がついてても変換してくれる。
第二引数の設定で、二進数や十六進数表記の文字列からも変換できる。
parseFloat( "2円", 10 );
加えて小数点以下を切り捨ててくれる。
parseInt( "2.8円", 10 );
数値から文字列へ
推奨。
String( 2 );
裏技っぽい方法。
"" + 2;
`${ 2 }`;
数値に限らず、すべてのクラスに基本的についている方式。
2.toString();
終わりに
という感じで[変数]に代入できる JavaScript の値「文字列(String)」と「配列(Array)」のを2つ紹介しました。
「数値(Number)」にはなかった可能性を感じてもらえれば幸いです。
これら2つの値はツクールの[変数]に代入して使うより、コアスクリプトのメソッドやプロパティが返す値を使う方が多いかもしれません。
その方法については…また長くなるので機会があれば。
ちなみに「真偽値(Boolean)」についてはほとんど書いてませんけど、要は[スイッチ]なので[変数]に格納する意味がないので割愛しました。
あと他のクラスも[変数]に代入できるんですが、説明が面倒臭いわりに便利でない気がするので説明はなしです。
あと、配列のループ処理は説明したほうがいいのかなーと思ってますが、機会があればそのうち。
とはいえ皆さんも、もう一年ぐらい[スクリプト]を使ってゲーム作ってますから(前提)、そろそろ普通に「JavaScript + 調べたいこと」で検索した記事も読めるようになってきたんじゃないかと思います。
レッツエンジョイ、ツクールライフ!
Discussion