プラグイン不要!意外と知られていない「メタデータ」の活用法

注:この記事はツクールフォーラムアドベントカレンダー12日目の記事です。
  この記事はRPGツクールMV・MZを対象に書かれています。ツクールMZのエディタで説明を行っていますが、ツクールMVにもそのまま利用可能です!


 突然ですが皆様は、こんな事態に遭遇したことはありませんか?
2020-12-12_09h52_18.png
機械系と虫系にだけ効くスキルを作りたくて!属性を作ったのに!どうしてスキルに設定できる属性は一つしか無いんだ!
……とか。

そんなの簡単さ、#12に「対機械・虫」の属性を入れればいいんだ」と思っても、
うっかり仕様書に「属性付与が載る」だなんて書いてしまっていたらどうすればいいのでしょう?

 こういう場合、多くの人はその仕様を諦めたり、複合属性を実現するプラグインを探したり、あるいは「えーいもう知るもんかこんな出来損ない」と言って作中の登場人物を全滅させるようシナリオを書き換えるかと思います。
 もしかすると、ダメージ計算式欄に
JavaScript:
(a.atk*4-b.def*2)*b.elementRate(10)*b.elementRate(11)
なんて書いて解決しちゃうおませさんもいるかも知れない。

 今回ご紹介するのは、そんな皆様(特に3番目)に送る新たな選択肢。「メタデータによる設定」です。

 さて、まずは「メタデータって、何だ?食えるのか?」という方向けに、メタデータが何かという説明から始めましょう。ツクールMV・MZのスクリプトについて説明する方はいても、メタデータについて触れている方は現状皆無であるというのが私の認識です。
 私が確認した唯一の例が、このページの中盤にたった1文、
ちなみに $dataActors[アクターID].note でメモ欄の内容もそのまんま取得できますよ。
と書いてあるだけです。ほんとにこれだけです。

 ここまで書いて「メモ欄……?あっ、もしかして」と思った方もいるでしょう。プラグインの設定時によく見る、
<xyz:555>
みたいな記述をメモ欄にするアレです。これこそが「メタデータ」なのです!

では、早速メタデータの使い所を見てみましょう。まず、データベースの「敵キャラ」のメモ欄にこんなふうに書いて下さい。
<deBug:3>
("deBug"の部分には英数字なら何を入れても大丈夫です。大丈夫じゃない文字もあるかも知れませんが、アルファベットで書けば間違いないと考えて下さい)
そして、スキルのダメージ計算式に次の文字列を入れます。
JavaScript:
$dataEnemies[b._enemyId].meta.deBug
これは「敵データのメモ欄にある"deBug"という項目の値を読み取るよ!」という意味の文です。b._enemyIdが相手の敵キャラのIDですね。詳しい説明は詳しい人に任せます。とりあえず今は設定した"deBug"を参照できるということがわかればいいのです。
これをさっきの基本ダメージと組み合わせれば、
JavaScript:
(a.atk*4-b.def*2)*$dataEnemies[b._enemyId].meta.deBug
 これで「属性付与と両立できるタイプの虫・機械特攻スキル」の完成です!……しかし、これだけで「ワア、便利!早速今日から使って見よーっと!」なんて言う人はいないでしょう。
 これだけなら上記のb.elementRate(11)の方がよっぽど便利です。だってこんな回りくどくて長い記法覚える必要ないし、この書き方だと味方へ攻撃するスキルには使えないし、そして何よりメモ欄にメタデータを書き忘れただけでダメージが0になってしまうし。
(参考映像)
(「ドロン」のメモ欄にだけメタデータを書いています)

 しかし、この「メタデータ記法」にできて「属性記法」にできないことがあります。「属性記法」ではゲームデータのjsonファイルを直接イジったりしなければ1000%(=10)以上の値は入れられませんが、メタデータならどんな値でも入りますし、そもそもそれが整数である必要もありません。それどころか文字列を入れることすらできちゃうんです!
 それではやってみましょう。スキルのダメージ計算式にこう記入します。
JavaScript:
$dataEnemies[b._enemyId].meta.deBug + a.atk*2 - b.def*2
 この式、見覚えがあるのではないでしょうか。これはツクールMV・MZにて一般的に用いられている魔法攻撃のダメージ式と同じ形です。敵ごとにdeBugの値を変更することで、属性とはまた違ったアプローチで「機械と虫にだけ大ダメージを与えるスキル」を実現できましたね。
 では、実際に動かしてみましょう。さきほどの「虫ケラ」のdeBugを50、「ドロン」のdeBugを100にしてダメージの差を観測します。
(参考映像)
……アレ?

ここで予想外の事態が入りました。上述の計算式だとどういうわけだか予想の50倍くらい高いダメージが出てしまいました。この記事を書いている途中で気づいたものなので完全な予想外です。とりあえず、ダメージ計算式をこのように書き換えてみてください。
JavaScript:
$dataEnemies[b._enemyId].meta.deBug  - b.def*2+ a.atk*2
すると今度は想定通りの結果になります。「虫ケラ」と「ドロン」に与えるダメージ差がだいたい50くらいであることを確認してください。
(参考映像)

 それにしても、どうしてa.atk*2とメタデータ参照を隣り合わせにするとダメージが膨れ上がってしまったのでしょう?教えて偉い人(講座系の記事で執筆者が教えを請うなんて前代未聞ですね)。
(ちなみに式を「a.atk*2+$dataEnemies[b._enemyId].meta.deBug - b.def*2」にしても同様の現象が起こるようです。この場合、「虫ケラ」へのダメージが5000くらいで「ドロン」へのダメージが5万くらいになります)

 最後に、現在RPGツクールMVで制作中のゲーム「WAVEBATTLE!」で実際に行っている「メタデータの文字列参照」をお教えして、この記事を締めたいと思います。先ほど私はメタデータに「文字列を入れることができる」と書きました。これを使えばプラグイン無しで「ラ○と魔法」シリーズみたいな敵鑑定スキルが作れます!
 早速やってみましょう。デフォルトデータベース1番の「ゴブリン」さんを鑑定してみることにして、メモ欄に次のように書きます。
<desc1:人間に比べれば知能も品性も無い野蛮な文化を営む魔物。>
<desc2:だが彼らを滅ぼそうとする我々が野蛮でないと言えようか?>
これを書いたからにはそれを読み込む処理が必要ですよね?今度はそれを書きましょう。
新しいスキルのダメージ計算式にこう書いて下さい。(行を分割してますが実際には1行に連続して書いて下さい)
JavaScript:
$gameMessage.add($dataEnemies[b._enemyId].meta.desc1);
$gameMessage.add($dataEnemies[b._enemyId].meta.desc2);
b.result().used=0;
範囲は「敵単体」、使用可能時を「バトル画面」にして、そのスキルをゴブリンに対して使ってみてください。
うまくいけばこうなります。
2020-12-12_15h34_30.png

 先ほど書いた「ゴブリン」の説明文が表示されました!もちろん、まだここから改善の余地は山程あります。例えば、下が2行余っていますが、これを「desc3」「desc4」を入れてさらに説明文を付け足してもいいですし、b.hpなどを使ってHPやステータスを表示してもよいと思います。他にも、
JavaScript:
$gameMessage.setBackground(1);
$gameMessage.setPositionType(1);
 これを冒頭に足せばメッセージウィンドウの位置や背景を変更できたりします。これに関しては書こうと思えばいくらでも書けるのですが、本題のメタデータとは関係ないのでここでの言及はここまでにしておきます。

 長くなりましたが、本記事はこれで終了です。
 ツクールフォーラムアドベントカレンダーは第1回が行われたときから知っていますが、このように記事を寄稿したのは初めての経験となりました。そのため書く文章量や構成が掴みきれなかったり、一度1から全部書き直したりして、気づけば16時近くの投稿となったことを1~11日目までバトンをつないでいただいた皆様には申し訳なく思っています。

 さて、今回は意外とだれも教えていない「メタデータ」について、私が知る限りのことを記しました。この記事をご覧になった皆様のうち一人でも、お役に立ったなら幸いです。あと、中盤の「なぜか5万ダメージを叩き出す計算式」の原因ですが、何かご存知の方がいらっしゃったらこのスレの返信という形で追記してください。

 それでは今度こそ、この長い記事をお読みいただきありがとうございました!
 明日の記事はwingly m_tさんの「日にちや曜日がトリガーの戦闘イベント 」です。
 こちらからお読みになれます!
 
最後に編集:
登録しました!これで記事執筆は一段落です。
 
こちらで「なぜか5万ダメージを叩き出す計算式」 を検証してみました。
メタデータは「文字列」として出力されます。
そして文字列を+で合わせると、文字通り繋げることができます
例えば "RPG" + "ツクール" + "MZ"とすると"RPGツクールMZ"という文字列が
出力されるわけです。
そしてこれには、JavaScriptの文字列と数字に対する仕様も影響しているようです。

これを踏まえて「$dataEnemies[b._enemyId].meta.deBug + a.atk*2 - b.def*2」という式を検証します。
ここでは$dataEnemies[b._enemyId].meta.deBugに1000、そして
アクターの攻撃力とエネミーの防御力を10とみなして検証しましょう。

$dataEnemies[b._enemyId].meta.deBugは、文字列1000を出力します。
そしてこれに、a.atk*2の値を文字列に変換して接続します
これが行われることにより、攻撃力が10であれば
"1000" + "20" = "100020"という文字列が出力されます。
さらにこれを、マイナスがあることによって数字に変換され
防御力が10であれば100020 - 20 = 100000というダメージが算出されるのではないでしょうか。

一方「$dataEnemies[b._enemyId].meta.deBug - b.def*2+ a.atk*2」であれば
$dataEnemies[b._enemyId].meta.deBugの1000を数字とみなして計算を行うので
想定通りの値になると考えられます。
 
最後に編集:

panda

ユーザー
シトラスさんが書かれたように、metaで取得した内容が文字列になっているせいですね。
Number($dataEnemies[b._enemyId].meta.deBug)
とか
($dataEnemies[b._enemyId].meta.deBug - 0)
とかで数値に変換してやるようにすれば、計算の順番を気にしないで済むと思います。
けっこうな落とし穴ですよね……。
 

DarkPlasma

ユーザー
中盤の「なぜか5万ダメージを叩き出す計算式」の原因ですが、何かご存知の方がいらっしゃったらこのスレの返信という形で追記してください。

メタデータが文字列として評価されているためです。正しい結果を得たい場合は Number($dataEnemies[b.enemyId()].meta.deBug) などとして数値に変換しましょう。

js は2つのオペランドの型が異なる場合、暗黙的に型変換を行います。
文字列と数値を加算する場合は文字列型に変換してから加算処理、つまり文字列の連結を行います。
一方、減算や乗算の場合は、数値型に変換してから演算処理を行います。

一見便利ではありますが、今回のケースのように予期せぬ不具合の元になりますので、数値として扱いたい場合は明示的に数値型に変換してから用いるのが良いでしょう。
暗黙的な型変換は避けるべきものです。
 
メタデータは「文字列」として出力されます。
シトラスさんが書かれたように、metaで取得した内容が文字列になっているせいですね。
一見便利ではありますが、今回のケースのように予期せぬ不具合の元になりますので、数値として扱いたい場合は明示的に数値型に変換してから用いるのが良いでしょう。
暗黙的な型変換は避けるべきものです。
 皆さん、ご指摘ありがとうございます!メタデータはあくまで文字列だったわけですね。
 
 さて、まずは「メタデータって、何だ?食えるのか?」という方向けに、メタデータが何かという説明から始めましょう。ツクールMV・MZのスクリプトについて説明する方はいても、メタデータについて触れている方は現状皆無であるというのが私の認識です。

宣伝不足なのかなんなのか、GitHubはなぜか検索上位に出てこないということもありますけど。
MVとMZのリファレンス作ってます!! 活用してねっ!!
(なおMZはまだMVを引き写しただけみたいな感じです)
 

んーぞー

ユーザー
メタデータというものの存在をここで初めて知りました、ご紹介ありがとうございます!
今までデータにプロパティを追加するとき、わざわざJSONファイルを自作して参照させてましたがこっちの方が断然スマートですね!


宣伝不足なのかなんなのか、GitHubはなぜか検索上位に出てこないということもありますけど。
MVとMZのリファレンス作ってます!! 活用してねっ!!
(なおMZはまだMVを引き写しただけみたいな感じです)

>とんび様
まるで公式かと見紛うような素晴らしいリファレンスですね!
ありがたく参照させていただきます!
 
トップ