投稿記事

折尾楽太郎 2022/04/30 17:00

(0007)RPGツクールMVツール「SAKAN - タイルセットビルダー -」について

概要

RPGツクールの公式ツール「SAKAN - タイルセットビルダー -」(以下SAKAN)が気に入ったのですが、ネット上での情報がかなり少なく、若干癖のある操作感だったので、使い方を書き書きしておこうかと思います。

前置き

RPGツクールMZでゲーム制作をしていますが、タイルセットがA~Eまでしか設定できないのって不便に思ったことありませんか?私の場合、基本的にファンタジー世界観なのですが、ATMと自販機が存在する感じなので、ファンタジー関連のタイルセットとSF内装のタイルセットを併用しなければならず、そこに採集用の草やら石やらのタイルセットも配置したいとなると、A~Eの5つでは足りなくなってくるんです。

ただ、SF内装のタイルセットで必要なのはATMの2マスと自販機の2マスの計4マスだけ…。であれば必要な分だけ集めて一枚のタイルセットにすればいいんじゃない?というお話になります。

Photoshopを持っているのでそれをやってみたんですが、如何せん仕事で使っているわけではなく、使いこなせていないこともあり、凄く時間がかかった上にうまくできませんでした。

具体的には…

  • タイルをちゃんと並べたつもりなのにどこかでずれてしまう
  • 背景が透明のタイルの場合、画像を真ん中に配置しようとしても寄ってしまう

という感じでした。恐らくちゃんと調べたら解決するツールとかあるんだろうなと思いますが…。

で、SAKANを導入してみたんですが、正直?????でした。説明書読まない人間なので、取り敢えず触ってみたところよく解らず…。

ネットで検索してみても使ってる人が少ないのか、情報がほとんど落ちてない…。

というわけで、慣れれば結構いいツールだと思ったので、勝手におすすめするとともに、ざっくり自分が困ったところと使い方を書き残そうと思います。

あ、因みにTwitter等でもときどきおすすめしていて回し者感が出てますが、SAKANの売り上げが伸びても私には1円も入らないので悪しからず。

※公式さんの許諾等も取らずに勝手に書いているので問題があれば教えてください。必要に応じて修正/削除いたします。

SAKANのマイナスポイント

回し者感を希釈するために先にネガティブなポイントを挙げておきます。


・ツクールMV本体が必要
SAKANは「RPGツクールMVツール」なのでMV本体が必要です。私のようにMZから入った方には「え?」と思われるポイントだと思います。MVのプロジェクトを読み込み、MVのプロジェクトで書き出す方式なのでMZで代用…ということもできません。MVとMZは画像系素材の規格が共通なので、素材集という意味合いでMV本体を購入することも個人的には良いと思いますが、皆さんの予算感次第というところですね。


・操作感に癖がある
SAKANはタイルセットだけでなくタイルも自作できます。素材となる画像がスタンプのように使え、それを組み合わせたり、ペンで線を書き加えたり、色調を変えたりできます。が、例えばスタンプで画像を置き、ペンツールに切り替えると画像が消えます。作成した画像を保存しようとしてフロッピーのアイコンをクリックし、保存先のフォルダーを指定すると「エクスポートが失敗しました。」と出ます。タイルセットにタイルを配置し、その隣に次のタイルを置こうとすると前のタイルが消えます。

どゆこと?????(後ほど解説します)


・何の画像か解らないのがちょこちょこある
これはRPGツクール全般に言えることですが、タイルパレットの画像が小さいので、正直何の画像か解らないのが結構あります。作成している画像の方は拡大できますが、元になる画像はできないので、別途Windows標準搭載の画像表示アプリ等で開いて拡大して確認する必要があります。(マウスポインターを当てても名前は表示されませんw)


・重ねる順番の概念が無さそう
これを書くのはちょっと酷かもしれませんが、レイヤーや重ねる順番の概念が(私の知る限り)ありません。なので、何か図形を描いた後に、その下に画像や図形を重ね合わせようと思っても(たぶん)できません。重ねるときは下から順番に描くしかない(と思われる)のが難儀ですね。

SAKANの良いところ

じゃあ何が良いのさ?ということで良いところを。


・タイルを並べるのが楽
タイルのサイズが48px×48pxが基本単位(だったかな?)ですが、それで固定されているので、画像編集ソフトで調整するときにマウスのドラッグで細かい微調整をしたり、ミスって隣のタイルの画像が微妙に見切れたり…といったことは起こりません。


・タイルの素材集として
公式さん曰く、組み合わせて使えるパーツデータが1000種類以上同梱されているということで、ドット絵描けない勢の私としてはありがたかったです。勿論組み合わせたり、更に描き加えたりできるツールなんですが、そのパーツそのものをタイルとして書き出しても充分使えるものが多いです。


・安い
これをおすすめポイントに書いていいのか悩ましいですが、当記事執筆時点で定価1518円、GWセールで455円で販売されています。前述のパーツデータが入っていてこの価格はお買い得じゃないかと思います。MV本体持っていない方はセール期間外だとMV本体が…ですが、セール期間内であれば検討の余地ありかと…。これまた前述の通り素材集としても有用ですからね。

SAKANの使い方

①MVプロジェクトを開く

起動するとこんな画面が開きます。

まずはMVのプロジェクトを読み込みます。画面左上の「ファイル」から「MVプロジェクトを開く...」をクリックしMVのプロジェクトを開きます。



②タイルを描く

左にあるタイルパレットみたいな部分がパーツです。使いたいパーツをクリックすると中央の枠(以下キャンバス)に表示されます。

この状態で画像をドラッグアンドドロップすることで画像の位置を調整できます。
↓こんな感じ

で、この位置を調整した状態で隣に別の画像を置いてやろうとパレットをクリックすると…

Oh, my goodness! せっかく調整した画像が消えてしまいました。

実はパーツの配置を定めた後、確定操作をしなければならなかったんですね。(私はこれに気付くのに結構時間がかかりました)

やり方は簡単。位置を定めた後Enterを押すかクリックでOKです。

確定してもキャンバス上は特に見た目が変化しませんが、パーツ画像を動かしてみると、キャンバスに画像が反映されていることが解ります。(なのでパーツ画像のことをスタンプみたいなものだと思ってます)

この状態であれば別のパーツを選択したりペンツールに切り替えても大丈夫なので、これを繰り返してお好みのタイルを作成しましょう。

尚、パレット上部の「インポート...」ボタンをクリックすることで画像ファイルを読み込んだり、「MV」タブをクリックすることで読み込んでいるMVプロジェクトに含まれるタイルセットをパレットに呼び出すことができるので、MVやMZのタイルセット、その他無料、有料素材もスタンプとして使用することができます(素材については必ず規約を確認し、許可されている範囲で使用してください)。

↓Photoshopで色調を変えたMZのタイルセット画像をインポートした図

因みに色調変更はタイルセット単位で行うならPhotoshop等の画像編集ソフトで一気にやった方が早いですが、タイルチップ単体ならSAKANの右下の色合いと明るさボタンから調整することも可能です。



③タイルを書き出す

さて、タイルができました。ではこれを保存しましょう。ちょうど右下にそれっぽいフロッピーアイコンがあるのでクリックしてみると、「エクスポートフォルダーの選択」というウインドウが表示され、書き出し先を指定できるようです。

解りやすく「sakan」というフォルダーを作ってそこを指定してみました。

……は?( ゚Д゚)

何度やっても同じ結果。画面上部の「ファイル」→「ユーザーパレットをエクスポート...」からやっても同じ結果。保存先が悪いのかと別の場所を指定しても同じ結果。

保存できんやん。どゆこと?しかも何がダメなのか、何ならツール側のバグなのか操作ミスor使い方が間違ってるのかも、どうしたらいいのかも全く解らない。

私はここで挫折して数ヶ月放置しました。おかげでツールを購入してから活用できるようになるまでに結構な時間(期間)が…。

実はこの問題の解決策はこの記事執筆中に発見しましたw
じゃあこれまでどうしてたのか?についても後述します。

画面左上の「ユーザー」タブをクリックして「追加」ボタンをクリックすると、パレットに作った画像が登録されます。

これを行った後に上記の保存手順を実行すると…

できたし。マジか。


ではこれまでどうやってたかも説明しておくと、画面右上に「書き出す」というタブがあるのでそれをクリックします。

するとこんな画面に切り替わります。

キャンバス側には読み込んでいるMVプロジェクトのタイルセットが出現し、その左上に選択中のタイルが。「タイルセットを選択」の枠内のプルダウン2か所を切り替えることで表示するタイルセットを切り替えることができます。

つまりはMVプロジェクトのデータベースにて、タイルセットとして設定されている画像が表示されているわけです。

ここにパレットで選択されている画像を載せて置換するわけですね。で、一つ目を置換するために配置を定めてEnterを押して(orクリックして)次の画像をパレットで選択すると…

ふぁっ!?( ゚Д゚)

そうなんです。さっきのEnter(orクリック)は全くの無意味で、一旦画面下部の「名前を付けて保存...」をクリックし、画像を書き出さないと置換が反映されないんですね。

え?じゃあどうやって作ってたのかって?そうですよ!一枚一枚書き出し→読み込みを繰り返して作ってましたよw

そんな面倒なことをしなくてもいいことを今日知りましたwww

ふぅ(-_-)

え、じゃあもしかしてMVのプロジェクト無くても動く?と疑問が湧きましたが、流石にアンインストール→インストールしてまで試す元気はありません…。知見をお持ちの方は教えていただけると幸いです。

まとめ

というわけで、文句もいろいろ書いてしまいましたが、使いこなせれば凄くいいツールだと思ってます。SAKANにもたくさん素材が入ってますし、無料/有料素材を含めると数えきれないほどの素材があるわけですが、1つのタイルセットに読み込めるのは5つまで…。集約したい!という場合や、ドット絵は描けないけどマップチップにこだわってみたいという方にはおすすめできるんじゃないかと思っています。

特に、タイルによっては、カップが右上にしかなく、キャラを向かい合って座らせても片方しかカップが無いみたいなことが起こったりするので、そういう場合に同じ画像を左下に追加配置するみたいな感じであればSAKANでお手軽にできます。

本当は使い方動画みたいなのを作りたかったんですが、現状動画を作ったことが無く、編集ソフトも未インストールな上、GWはゲーム制作に充てようと決めていたのでCienの記事にさせていただきました。これから動画編集に手を付けるとなると、GWそのものを持っていかれそうな気がしますから…。

それではそろそろ制作に戻りたいと思います。夏ぐらいには完成させたいなぁ(-ω-)

今回はこの辺で。ではでは。

折尾楽太郎 2022/03/11 08:00

(0006)RPGツクールで数学を活用してみる

概要

高校数学(今は違うかも)で学ぶド・モルガンの法則がRPGツクールやプログラミングで役に立つ(かもしれない)というお話です。

前置き

最近プラグイン作ってないのでちょっと数学ネタを。

さて皆さん、数学してますか?日常生活でも大活躍ですよね!あ、でも数学嫌いな方もいらっしゃるかな?もし要点だけ知りたいという方がいらっしゃったら適宜読み飛ばしてください。

ド・モルガンの法則

ご存じない、またはもう忘れたよ!という方のために、ざっくりド・モルガンの法則を説明しておくと、ある集合Aとある集合Bがあるとして、AとBの共通部分の補集合はAの補集合とBの補集合の和集合と同じだよ~っていう法則です。

あ、今回は凄くざっくり説明してるので、数学的に突き詰めると「そこ違うんじゃない?」や「正確性に欠ける表現だ」みたいになるかもしれませんがお目こぼしを…。

文字で書くと解りにくいですよね。申し訳ないんですが、ググっていただければ解りやすい図がたくさん出てくると思うので、そちらを適宜参照してください。

で、これがですね、条件分岐にも使えるんですよ。共通部分はand(且つ)、和集合はor(または)に置き換えられるので、例えば「A且つBのとき」と「AじゃないまたはBじゃないとき」は同じで、「AまたはBのとき」と「Aじゃない且つBじゃない」も同じになるんです。

「ふ~ん、で?」という方もいらっしゃれば「あ~、ね」という方もいらっしゃるかと思いますので、ちょっと実例を見ていきましょう。

活用例

例えば、関所のイベントで、通行証を持っているか、王様がパーティーにいれば門番の前を素通りできるようなシチュエーションを考えてみましょう。

RPGツクールのイベントコマンドでそのまま書くとこんな感じですよね。

◆条件分岐:パーティーが通行証を持っている
 ◆注釈:何もしない
 ◆ラベルジャンプ:処理終了
 ◆
:それ以外のとき
 ◆文章:門番
    :待て!ここは関係者以外通行禁止だ!
 ◆移動ルートの設定:プレイヤー
          :◇一歩後退
 ◆ラベルジャンプ:処理終了
 ◆
:分岐終了
◆条件分岐:王様がパーティにいる
 ◆注釈:何もしない
 ◆
:それ以外のとき
 ◆文章:門番
    :待て!ここは関係者以外通行禁止だ!
 ◆移動ルートの設定:プレイヤー
          :◇一歩後退
 ◆ラベルジャンプ:処理終了
 ◆
:分岐終了
◆ラベル:処理終了

……、え~っと、私は結構ラベルジャンプ好きで活用してるんですけど、皆さんどうです?勝手なイメージなんですけど、ラベルジャンプって使ってる方は少数派なんじゃないかなと…。勿論スイッチを使う等でラベルジャンプを使わなくても実現できますのでご安心を。

それはともかく、ちょっとややこしいですよね。条件がまたは(or)なので、条件分岐を2つに分けないといけない上、ラベルジャンプを使う等の工夫をしないと、通行証を持っていても王様がいなかったら結局止められてしまったり、どちらも満たしていない場合は2回も怒られてしまったりという残念なバグに…。

加えて、条件を満たす場合(上記でいう注釈の部分)に何も処理をしないという、若干無駄なことをしているような書き方になっています。

ド・モルガンの法則を使ってみよう

では、ド・モルガンの法則を活用してみましょう。「AまたはBのとき」と「Aじゃない且つBじゃない」が同じ意味になるんでしたね。今回の例に当てはめると、【「通行証を持っている」または「王様がパーティーにいる」】なので、【「通行証を持っていない」且つ「王様がパーティーにいない」】ですね。

これを書いてみると…

◆条件分岐:パーティーが通行証を持っている
 ◆注釈:何もしない
 ◆
:それ以外のとき
 ◆条件分岐:王様がパーティにいる
  ◆注釈:何もしない
  ◆
 :それ以外のとき
  ◆文章:門番
  :  :待て!ここは関係者以外通行禁止だ!
  ◆移動ルートの設定:プレイヤー
  :        :◇一歩後退
  ◆
 :分岐終了
 ◆
:分岐終了

通行証を持っていなくて且つ王様もパーティーにいない場合にのみ門番に絡まれればOKになったので、ちょっと処理が簡単になりました。ラベルジャンプも不要になりましたね。

でも、「何も処理をしないという、若干無駄なことをしている」っていう部分が解決してなくね?とお思いのあなた!その通りです。

JavaScript等であれば、変数の前に「!」をつけたり、「!==」で比較することで、ここでいう「持っていない」や「いない」を簡単に表せるので、

◆条件分岐:パーティーが通行証を持っていない
 ◆条件分岐:王様がパーティにいない
  ◆文章:門番
  :  :待て!ここは関係者以外通行禁止だ!
  ◆移動ルートの設定:プレイヤー
  :        :◇一歩後退
  ◆
 :分岐終了
 ◆
:分岐終了

みたいな書き方ができるんですが、ツクールの仕様上、そういった機能が備わっていないので、

・通行証を入手した時点でスイッチをONにするようにして、スイッチがOFFの場合で条件分岐する
・スクリプトを使う

等をしないとここまでの簡略化ができないのが残念です。

ド・モルガンの法則の使いどころ

恐らくですが、and(且つ)よりもor(または)の方が条件分岐を書くときに難易度が高いんですよね。それもそのはずで、例えば条件Aを満たす場合は十の位が1、満たさない場合は0、条件Bを満たす場合は一の位が1、満たさない場合は0とした場合、and(且つ)の場合は11の場合のみ見ればいいわけですが、or(または)の場合は11の他に10、01の場合もケアしなければならないので、確認内容が膨れ上がるのは当然です。

「じゃあ00の時だけ除外すればいいんじゃね?」と思った方は正しくド・モルガンの法則を活用できてます!その調子で行きましょう!

というわけで、条件分岐の条件が複数ある場合は、上手くやればor(または)とand(且つ)は相互に変換できるよ。ということと、「~じゃない」という条件も上手くやれば「~である」に変換できるよ。というお話でした。皆さんの制作の一助になれば幸いです。

今回はこの辺で。ではでは。

折尾楽太郎 2022/02/06 23:00

(0005)特徴の追加作戦の続報の続報

概要

(0004)特徴の追加作戦の続報で初期化のひと手間が必要な旨を記載しましたが、それを解消することができました。あと、思い切って自作プラグインを公開してみました。

ニューゲーム時に発火する処理あるじゃない

前回の(0004)特徴の追加作戦の続報で、ロードをしたあとにタイトルに戻ってニューゲームを選ぶと、特徴が変化したままニューゲームが開始されてしまうため、初期化のプラグインコマンドを別途用意した旨を記載しましたが、rmmz_manager.js内にDataManager.setupNewGameというメソッドがありました。なんでこれまで気づかなかったのかが謎ですが、どう見てもNewGameの際に発火するイベントですよね。

というわけで、前回紹介した再定義を使ってDataManager.setupNewGameの処理に初期化の処理を挿し込み、プラグインコマンドで処理をしなくても初期化できるようになりました。

ちょっとしたぼやきのその後

前回、使ってみたいよ~という方はTwitterに…と書きましたが、思い切って公開してみました。

【自作プラグインリスト】
https://r-orio-rpg.halfmoon.jp/rpgmaker/plugins/plugin_list

やっぱり連絡したりするより数クリックでダウンロードできた方が手軽でいいですよね。

短いですが今回はこの辺で。ではでは。

折尾楽太郎 2022/01/22 19:00

(0004)特徴の追加作戦の続報

概要

(0002)特徴の追加作戦で問題点を認識していながら解決できていなかった部分を解決できました。

あと、当時はコアスクリプトを直接いじるという暴挙に出ましたが、そんなことをしなくてもいいことが判明しました。

コアスクリプトを直接いじらなくてもよかった

前回コアスクリプトをいじるという暴挙に出ましたが、実は公式さんのプラグイン講座「公式プラグインを読み解く」のページに「既存メソッドの再定義」という項目があります。プラグインを触り始めた当初は意味が理解できず、スルーしていましたが、これが超重要でした。

<引用ここから>

プラグインは、そのコアスクリプトが定義する関数を『再定義』することでMZのゲーム動作の変更を可能にします。
以下が再定義の基本的な書き方です。

const _Game_Picture_show = Game_Picture.prototype.show;
Game_Picture.prototype.show = function() {
_Game_Picture_show.apply(this, arguments);
// do something
};
まず、1行目で、変数『_Game_Picture_show』を宣言し、コアスクリプトの関数『Game_Picture.prototype.show』を代入しています。
そして2行目で関数『Game_Picture.prototype.show』を新しく定義し直します。
最後に、3行目で変数『_Game_Picture_show』に代入していた関数を実行しています。
applyというのは変数に代入していた関数を実行するための関数(メソッド)です。

この一連の処理により何が行われるかというと、コアスクリプトの関数『Game_Picture.prototype.show』の元の処理を呼び出したあとで、新しくプラグイン作者が追加したい処理を追加しています。
このようにして関数の再定義を繰り返しつつ、プラグインは作られていきます。

<引用ここまで>

イメージとしては、元々ある「ツクールデパート」という建物をそのまま「旧ツクールデパート」という建物に入れて、もっと大きな建物を建設して名前を「ツクールデバート」にし、その建物の中に「旧ツクールデパート」を入れて、残りのスペースで+αのことをする…みたいな感じですかね。「ツクールデパート」を訪れると、元々のツクールデパートの内容(ここでは旧ツクールデパート)も丸々あって、追加されたものもその流れで見れるという感じ…。

わかりづらいですよね、すみません…

で、話を戻し、なんでコアスクリプトをいじるという話になったのかを振り返ると、セーブデータにゲーム中の$dataActorsの内容が保存されず、$dataActorsはゲーム起動時にデータベースの情報から毎回生成されるから、ゲーム中にイベントコマンドでいじっても戻っちゃうという課題からでした。

というわけで、コアスクリプト内のDataManager.makeSaveContentsというメソッドを直接いじってゲーム中のdataActorsの情報をセーブデータに忍び込ませ、同じくコアスクリプト内のDataManager.extractSaveContentsというメソッドを直接いじってセーブデータ内から$dataActorsを読み込んでました。

ここで先述の既存メソッドの再定義を使うと、プラグイン側でDataManager.makeSaveContentsとDataManager.extractSaveContentsを再定義してやることで、コアスクリプトを直接いじる必要がなくなりました。

コアスクリプトに直接手を入れるのは悪手なので、皆さんもできる限りやらないようにしましょう。

既存メソッドの再定義の弱点?

ただ、ここで一つ問題が発生しました。上記の既存メソッドの再定義では、コアスクリプトに記載されている本来の処理の後にしか処理を追加できません。

「3行目で変数『_Game_Picture_show』に代入していた関数を実行」の前の行に処理を挿し込めば、本来の処理の前にも処理は追加できますが、本来の処理の中に処理を追加することは、少なくとも私の知識ではできません(方法をご存じの方がいらっしゃったら教えてください…)。

そのため、本来の処理を実行するのではなくコピペして、間に$dataActorsを保存、読み込む処理を挿し込んだもので置換する方式を採らざるを得ませんでした。

ニューゲームだと$dataActorsが更新されない問題

さて、問題の核心に迫っていきます。何が問題だったかというと、$dataActorsの変遷として、

【セーブ/ロードの場合(問題なし)】
ゲーム起動後データベースの情報が読み込まれて$dataActorsが生成される
ゲーム中にプラグインで$dataActors内の特徴が変化する
セーブするとセーブデータに$dataActorsの情報も書き込まれる
ロードするとセーブデータ内の情報から$dataActorsを再現して問題なし

【ニューゲームを再度選択した場合(問題あり)】
ゲーム起動後データベースの情報が読み込まれて$dataActorsが生成される
ゲーム中にプラグインで$dataActors内の特徴が変化する
セーブするとセーブデータに$dataActorsの情報も書き込まれる
タイトルに戻る($dataActorsは変化なし)
ニューゲームを選択する($dataActorsは変化なし)
ニューゲームなのに$dataActorsが変化したままになっているので問題あり

という感じになります。意図せず特徴が変化した状態ではじめからプレイできてしまうわけですね。

処理として問題になってくるのは、ロードの場合はその処理があったので、その処理を前述の方法で上書きし、$dataActorsをセーブデータから読み込んだ内容で上書きする処理を挿し込めましたが、ニューゲームの場合はデータベースから$dataActorsを作成するような処理がそもそも見当たらず、処理自体が無いので上書きする方法も使えないという点でした。

データベースの情報を取得するメソッドは見つけられた

で、いろいろ試行錯誤やコアスクリプトを読んだりした結果、データベースから情報を読み込んでいるメソッドを見つけました。rmmz_manager.js内のDataManager.loadDataFileというメソッドです。ここでよくわからんとなってしまったのがxhrでした。xhrはXML Http Requestの略で…(以下略)。

取り敢えずこれを使ってdataフォルダー内のActors.json等、データベースの内容をJSON形式で保存してあるファイルの内容を読み取っているようです。

ここで個人的に凄く疑問だったのが、メソッドが
xhr.send();
で終わっていることです。xhrは一行目で
const xhr = new XMLHttpRequest();
と書いてあるので、XMLHttpRequestのオブジェクトですね。

※補足
newは演算子の一つで、ざっくりいうと設計図を基に実体(オブジェクト)を作る処理をしてくださいという意味です。

「newする」という、プログラムを触っている人々には非常に聞き馴染みのある、逆に触っていない人々には「はあ?newは動詞じゃねぇしwww」と思われてしまう言葉がありますw

(補足ここまで)

で、sendは英単語で「送る」という意味ですよね。これでこのメソッドは終わりです。

…え?送って終わり?リクエストって、「情報くれよ~」でしょ?要求だけして処理なし?データベースの情報取得した後何もしないの???

と大混乱の中その日は就寝しました。

翌日、ちょっとこのXMLHttpRequestが気になってググってたところ、MDN Web Docsに情報がありました。JavaScriptを触る方々には御用達ですね。

結論から申し上げますとコールバック方式でした。

コールバックというのは、先にうまくいった場合はこうする、うまくいかなかった場合はこうすると先に決めておくようなイメージです。

例えば…

【当初の想定のイメージ】
おつかいを頼む

買ってきてもらったものを使って何かする(豆腐を冷蔵庫に入れる等)

【コールバックのイメージ】
おつかいを頼むときにメモに
「スーパーで豆腐を買ってきて冷蔵庫に入れておいて。売り切れだったら電話して」
と書いて渡す

みたいな感じでしょうか。

この例でいうと、「豆腐を冷蔵庫に入れる」処理を、おつかいから帰ってきたあとのところだけを見て探していたので見つからなかったわけです。

スクリプトに戻ると、xhr.send();の前にxhr.onload = () => 以下略という箇所がありました。ここでXMLHttpRequestの処理がうまくいった場合にどうしてほしいかを書いているようです。コアスクリプトではDataManager.onXhrLoadというメソッドをcallしてますね。

どうする?

少し話が戻りますが、ニューゲームの際に$dataActorsがデータベースの情報から生成or更新される処理が実行されていないことが今回の問題点でした。つまり、DataManager.loadDataFileを上書きしてあ~だこ~だしても、そもそも発火しないので意味がありません。

というわけで、似たメソッドをプラグイン内で用意して、別途データベースの情報を読み込むことにしました。

DataManager.loadDataFileでは、引数としてnameとsrcを取っており、それは前回のセーブデータに情報を挿し込んだ際にも触れたDataManager._databaseFilesで定義されていました。今回はActorの情報があれば充分なので、

nameは"$dataActors"、
srcは"Actors.json"

に置き換えてみました。

加えて、前述の通り、コールバックで取得した情報をどうするのかを記述するので、xhr.onloadで取得したデータベースの情報、特に今回は必要なのは特徴の情報なので、$dataActors[アクターのID].traitsを上書きすることにしました。

これを初期化というプラグインコマンドで呼び出すようにして、ニューゲーム開始直後に実行することで、別データで特徴を変更していても、ニューゲームを選択したら必ずデータベースの内容で上書きすることで戻せるようになりました。

プラグインユーザーの方にとってはひと手間必要になってしまいましたが、私のプラグイン作成能力ではこれが限界ということで…。

他の自作プラグインとの併用における問題

これまでの内容で一旦目的を果たせるプラグインにはなりましたが、別のプラグインでアイテムの使用効果を追加/削除するプラグインや、価格を動的に変化させるプラグイン等も作っています。

セーブデータに$dataActorsの情報を挿し込む処理とセーブデータから$dataActorsの情報を読み込む処理を追加しましたが、これらのプラグインにもセーブデータに

$dataItemsの情報を挿し込む処理とセーブデータから$dataItemsの情報を読み込む処理

が必要になりました。

「既存メソッドの再定義の弱点?」で記載した通り、この処理は本来の処理に処理を追加しているのではなく、処理そのものを置換しています。

ということは…、

このプラグインを読み込んだ後にアイテムの使用効果を追加/削除するプラグインを読み込むと、$dataActorsの保存/読み込む処理を挿し込んだしたものが$dataItemsの保存/読み込みを行う処理を挿し込んだもので置換されてしまい、$dataActorsが保存されなくなってしまいます。

というわけで、仕方なく$dataActorsと$dataItemsの両方を保存/読み込むようにしました。

その結果、両方のプラグインを読み込むと、セーブ・ロードの処理が$dataActorsと$dataItemsの両方を保存/読み込む処理を追加したものに2回置換されることになるんですよね。それもイマイチだなぁと思い、結局トリアコンタンさんのPluginCommonBaseのように、別のプラグインに置換を移管し、併用する方式にしました。

これですっきりしましたね。

ただ、置換にしたことによる不安はまだあり…。勘の良い方はお気づきかもしれませんが、他の作者さんのプラグインでDataManager.loadDataFileに手を入れているものがあると、恐らく競合するんですよね…。

というわけで、折角完成しましたが、公開していいものかどうか悩んでます。

ちょっとしたぼやき

いくつかプラグインを自作しましたが、アイデアが浮かんだときはテンションが上がり、需要あるかも?公開しようかな?へへへってなりながら作るものの、問題点が見つかり、打開策を講じているうちに「自分で使う分にはいいけど、人様に使ってもらうにはなぁ…」という感じになってしまい、こうやって工程を公開するだけに留まってしまっていたりします。それも毎回。なんか淋しいですね(-_-)

もし、「それでも使ってみたいよ~」や、「こうやったら既存メソッドの再定義の弱点のところ打開できるよ~」というお声がありましたら、Twitterの方にご連絡をいただけますと幸いです。

Twitter(折尾楽太郎@r_orio_rpg)

ではでは。

折尾楽太郎 2021/10/10 21:37

(0003)計算式でやりたい放題

概要

RPGツクールMZのデータベース「スキル」「アイテム」にある計算式で遊んだお話です。

計算式とは

RPGツクールMZでは、スキルやアイテムの効果のうち、ダメージや回復の量を計算式で指定することができます。計算式の入力欄にマウスカーソルを置いてしばらく待つと説明が表示され、記述方法のヒントを確認することができます。

内容としては以下の通りです。

<引用ここから>

使用者をa、対象者をbで表し、ドットに続けて以下のステータスを参照できます。たとえば「a.atk」は使用者の攻撃力を意味します。

atk 攻撃力
def 防御力
mat 魔法力
mdf 魔法防御
agi 敏捷性
luk 運
mhp 最大HP
mmp 最大MP
hp HP
mp MP
tp TP
level レベル

<引用ここまで>

これだけでも相当面白いスキルやアイテムが組めますね。敏捷性に依存した攻撃や運に依存した攻撃、レベルが上がると威力が下がる攻撃等々…。

ゲーム内変数を参照する

まずはこちらから。

  • $gameVariables.value(n) ※nは自然数

これでゲーム内変数n番の値だけダメージを与えられます。私の場合、預金残高を変数に持っているので、それを入れてみたところ、残高が100万G以上あったためエグいダメージを与えてしまいました。

Dateオブジェクト

もっとエグいのがこちら。計算式欄にもJavaScriptが使えるということで試してみたところ動きました。

  • Date.now()

DateはJavaScriptの標準組み込みオブジェクトで、.now()で現在時刻の世界標準時の1970年1月1日0時0分0秒からの経過時間(ミリ秒)(うるう秒は含まず)を取得できます。

執筆時点で約1,633,794,800,000でした。まさかの一兆超えです。ミリ秒(1000ミリ秒=1秒)だから仕方ないですね。興味があったらお試しください。笑えますよw

勿論後ろに「/1000/60/60/24」を付けることで単位を日にしたりも可能です。

三項演算子

いきなりプログラミング用語ですみません。でもこれ便利なんですよ。

三項演算子は【条件】?【条件に合う場合】:【条件に合わない場合】と記述します。
条件分岐といえばif文がメジャーですが、if文は一行に書くと可読性が下がるんですよね。
RPGツクールの計算式の入力欄は1行なので、三項演算子の方が相性が良い気がします。

尚、if文で書くとif(【条件】){【条件に合う場合】}else{【条件に合わない場合】}です。括弧の種類を間違えたり、過不足があると、通常は「unexpected token (」みたいにエラーが出て気づけますが、計算式の場合は問答無用でダメージが0になります。

例えばこんな計算式が考えられますね。

  • a.level % 2 == 0 ? 200 : 1000

a.levelは「計算式とは」で記載した通り使用者のレベル、%は剰余の演算子なので、「a.level % 2」の部分は使用者のレベルが偶数なら0、奇数なら1になります。

これまたプログラミング独特の記述ですが、==は「左辺と右辺が等しいかどうか」という意味です。つまり「a.level % 2 == 0」は使用者のレベルが偶数なら条件が成り立つ(true)、奇数なら条件が成り立たない(false)になり、前者の場合は:よりも前の200が、後者の場合は:よりも後ろの1000が採用されます。

使用者のレベルが奇数か偶数かによってダメージが5倍も違ってしまう、トリッキーなスキル/アイテムの出来上がりですね。Dateオブジェクトと組み合わせると、b.level % 5 == 0 ? Date().now : 0と記載することで、対象のレベルが5の倍数のときだけ1兆超えのダメージを与えるレベル5デスのようなスキルも作れますね。

因みに条件の部分はboolean(true/false(ツクール側でいうスイッチのON/OFF))の場合は比較演算子系(==、===、!=、!==、<、<=、>、>=)を使わなくても分岐できます。

なので、こういう記述も可能です。

  • $gameSwitches.value(n) ? (a.mat * 4 - b.mdf * 2) : (a.atk * 4 - b.def * 2)※nは自然数

以下と同じ意味になります。

  • $gameSwitches.value(n) == true ? (a.mat * 4 - b.mdf * 2) : (a.atk * 4 - b.def * 2)※nは自然数

これでn番のスイッチがONの場合はa.matとb.mdf、つまり使用者の魔法力と攻撃対象の魔法防御依存の攻撃になり、OFFの場合はデフォルトの攻撃と同じ計算が採用されます。

前回の記事で触れた、物語の途中で魔術師の通常攻撃を物理攻撃力依存から魔法攻撃力依存に変えることが可能になりますね。(攻撃アニメーション等は変更できませんが…)

尚、boolean(true/false(ツクール側でいうスイッチのON/OFF))は計算に使うときはtrue(ON)は1、false(OFF)は0として扱われるので、例えば

  • $gameSwitches.value(1) * 100 + $gameSwitches.value(2) * 10 + $gameSwitches.value(3)

にすると、スイッチ1がON、スイッチ2がOFF、スイッチ3がONなら101、スイッチ1がOFF、スイッチ2がON、スイッチ3がONなら11になります。

使えそうなJavaScript標準組み込みオブジェクト他

個人的に思う、使えそうなJavaScriptに搭載されているオブジェクトやメソッドを列挙します。

  • Math.abs(x):xの絶対値(計算結果がマイナスの場合一律0として処理されるので)
  • Math.ceil(x):x以上の最小の整数(小数点以下切り捨て処理をしたい場合に便利。ツクールの計算式は最終的な計算結果に小数点以下が含まれる場合、小数第一位が四捨五入される仕様の模様)
  • Math.floor(x):x以下の最大の整数(小数点以下切り上げ処理をしたい場合に便利。ツクールの計算式は最終的な計算結果に小数点以下が含まれる場合、小数第一位が四捨五入される仕様の模様)
  • Math.round(x):xの小数第一位を四捨五入
  • Math.log10(x):xの常用対数(10を底とした対数)(うまく使うと何桁かを得られる)
  • Math.max(x, …):引数の中で最大の値(上限値を設定したい場合に便利)
  • Math.min(x, …):引数の中で最小の値(下限値を設定したい場合に便利)
  • Math.random():0以上1未満の疑似乱数
  • Array.length:配列に対して.lengthを付けるとその配列の要素数を得られる

面白そうな変数・取得スクリプト

個人的に思う、使ったら面白そうなゲームデータを列挙します。

※公式さんのプラグイン講座から参照できるリファレンスより

  • $dataWeapons[id].price:武器の価格
  • $dataArmors[id].price:防具の価格
  • $dataEnemies[id].exp:敵キャラを倒したときに得られる経験値
  • $dataEnemies[id].gold:敵キャラを倒したときに得られるお金
  • $gameSystem.battleCount():戦闘回数
  • $gameSystem.winCount():勝利回数
  • $gameSystem.escapeCount():逃走回数
  • $gameSystem.playtime():プレイ時間(秒数)
  • a.isStateAffected(id):使用者が指定したidのステートになっているかどうか
  • b.isStateAffected(id):対象者が指定したidのステートになっているかどうか
  • $gameParty.members[n].isGuard():n番目の味方キャラが防御中かどうか
  • $gameParty.members[n].currentExp():n番目の味方キャラのこれまでに獲得した経験値
  • $gameParty.members[n].hasNoWeapons():n番目の味方キャラが素手かどうか
  • $gameParty.steps():現在の歩数
  • $gameParty.numItems(item):指定したアイテムの所持数

終わりに

計算式をいじれば、とんでもないぶっ壊れ性能のスキル/アイテムから、複雑な効果のスキル/アイテム、効果をフラグ管理できるスキル/アイテムなど幅広く作れそうですね。皆様も制作されているゲームに合った、面白い/興味深い計算式を考えてみては如何でしょうか。

ただ、お気をつけいただきたいのが、前述の通り計算式の入力欄は改行ができません。見たところ44文字辺りを超えると枠からはみ出るので一目で記述が確認できなくなってきます。

通常プログラミングをする際には、インデントや適度なスペース、改行を入れて可読性を確保(可読性:記述を読んで何をしているのかの把握のしやすさ)しますが、この入力欄では複雑な記述をするとあっという間に可読性が低下します。

恐らく外部エディターで記述を作り、別途メモとして保存した上で、最後に改行だけ削除し、コピペして反映する方が無難な気がしますね。

また、これも先述しましたが、通常JavaScriptで誤記があった場合はエラーで動かなかったり、DevToolsのコンソールでエラーが確認できますが、計算式の場合は単純にダメージが0になるだけです。

条件分岐でダメージが0になる可能性がある計算式の場合、正常に動作した結果、条件分岐でダメージが0になったのか、記述が間違っていてその結果ダメージが0になったのかが判別しづらいので、動作確認は慎重に行う必要がありそうです。

ではでは。

« 1 2

月別アーカイブ

限定特典から探す

記事を検索