プラグイン制作/技術|雑談

トリアコンタン

モデレーター
スタッフ
モデレーター
尾角つのさん

こんばんは!
試してみた限りではその記法でも問題なく動作しました。
ただ、セーブファイルに含めるクラスの場合、セーブ&ロードで復元したときに追加したフィールドが機能しなくなる場合があるようです。(定義方法次第で回避できるかもしれません)

また、セーブファイルに含めないかつ、既存クラスから継承しない場合、ツクールでもES2015のクラス構文が使用できるようですのでよろしければこちらも試してみてください。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes

ただしWebで公開する作品に含める場合、一部端末やモバイルブラウザで上記の記述が動作しない場合があるので、そこは注意する必要があります。
 
最後に編集:

尾角つの

ユーザー
トリアコンタン様いつもありがとうございます!
今では javascript も クラス構文使えるようになってるんですね!どんどん技術は進歩してて驚きます……

書き方のチェックしていただけて助かります。
上記の書き方だとファイル関連だと難しいんですね……気が付きませんでした(汗)
今はシーン関連を作成してるので問題ないですが、ゲームデータ関連もいろいろいじる可能性あるので、セーブファイルに含められる様な書き方模索しないとですね。
(先に function ClassAAA() {}; だけ一時関数の外側で定義してしまうとかですかね?)

頑張ります!
 

尾角つの

ユーザー
も少しだけ考えてみました。

var ModuleXXX = ModuleXXX || {};

(function($) { // 名前空間 ModuleXXX を $ にして扱う。

// クラスの作成
var _class = function ClassName() { // クラス名を定義する!
this.initialize.apply(this, arguments);
};

// スーパークラス
var _super = SuperClass;

// クラスの継承
_class.prototype = Object.create(_super.prototype);
_class.prototype.constructor = _class;

// グローバル関数化 (セーブデータに含める場合はグローバル化する。)
window[_class.name] = _class;

// 名前空間の関数化(グローバル化しない場合)
$[_class.name] = _class;

// クラスの初期化
_class.prototype.initialize = function () {
_super.prototype.initialize.call(this);
~~~;
};

// 関数A
_class.prototype.functionA = function() {
~~~;
};

~~~;

})(ModuleXXX); // (名前空間を渡す)

コンストラクタまわりを整えればセーブにも使えるかなって思って作ってみて、軽くテストした感じだとセーブ&ロードしてもちゃんと動作したのですが、これから、しっかりしたプラグイン作ってみて確認してみようかと思います。

追記:
return _class; 使ってて忘れやすかったので、即時関数内で名前空間に設定
 
最後に編集:

☆鶴香★

ユーザー
セーブの後にスイッチを入れるプラグインはあるけど、セーブの直前に変数を操作する…っていうプラグインが見つけられなかったので、JSは全然わかりませんが試行錯誤して自分で作ってみました。
ですが、オートセーブの処理を作ろうとしたら思ったようにいかなくなったので質問したいです。

メニューやセーブ画面を開くからセーブをしたセーブは、ロードしたときにMAPから始まります。
PHP:
$gameSystem.onBeforeSave();
    if (DataManager.saveGame(this.savefileId())) {
        this.onSaveSuccess();
    } else {
        this.onSaveFailure();
    }
たぶんこれでセーブしていて、セーブしたらセーブのSE、失敗だったらブザーが鳴ると思ったので

オートセーブのコマンドがきたら
PHP:
$gameSystem.onBeforeSave();
   if (DataManager.saveGame(DataManager.lastAccessedSavefileId())) {
        if(STsound == 1){
         SoundManager.playSave();
        }
    } else {
        if(STsound == 1){
         SoundManager.playBuzzer();
        }
    }
こうするようにしてみたのですが、(STsoundっていうのはプラグインパラメータでSEのON/OFFを切り替えられるようにと思って作った変数です)
これでセーブしたファイルをロードするとセーブのSEがなってから始まります。
this.onSaveSuccess();
のところでやってることに意味があるのかと思っていくつか試してみましたが、
私のやり方に問題があるのかもしれませんが、何が何だかわかりませんでしたorz

同じようにセーブしてから条件分岐させたはずなのに、
どうしてセーブ直後の処理が起きたり起きなかったりするのでしょうか?

また、セーブ後のSE等をロード時に起きないようにするにはどうしたらいいのでしょうか?

自分の勉強不足を棚に上げて質問するのはおこがましいようですが、ご教授いただけますと幸いです<m(__)m>
 
>鶴香さん、こん**は。
上記の件、添付のようなプラグインを試作して検証したのですが、
確かに状況が再現しました。

どうやら、オートセーブしたファイルをロードした時、
最初に「またオートセーブの関数が呼び出されている」ことが原因だと分かりました。

現在、対策を検討中ですので、今しばらくお待ちいただけると幸いです。

※余談:このあたり、イベントコマンドで「セーブの処理」をやっている人は詳しいんでしょうが、
僕はこのコマンドを使わない派なので:kaosigh:、今から解析して、原因を追跡します。
 

Attachments

最後に編集:

☆鶴香★

ユーザー
>神無月サスケさん
ありがとうございます!!プラグインの試作まで…!(ToT)
Scene_Save.prototype.onSavefileOkを直接書き換えると問題ないんですね
this.onSaveSuccess();が関係ないと分かっただけでも進歩です!ありがとうございます!!

正しい書き方なのか不安なのですが(^▽^;)
サスケさんが作ってくださったプラグインに下記を書き足してみました(駄洒落じゃないです)
PHP:
  var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
 Game_Interpreter.prototype.pluginCommand = function(command, args) {
   _Game_Interpreter_pluginCommand.call(this, command, args);
   if(command == 'TsurukaAutoSave'){
          if(args[0] == 'save'){
           Scene_Save.prototype.onSavefileOk();
       }
   }
 }
これで、プラグインコマンド TsurukaAutoSave save を実行してロードするとSEが鳴りました

Scene_Save.prototype.onSavefileOkが呼び出される前に何かあるってことですかね?
…調べようと思ったのですがScene_Save.prototype.onSavefileOkがどこでどういう風に呼び出されるのか分かりませんです…(´;ω;`)

迷惑でなければもう少しお力をお借りしたいです><
 

☆鶴香★

ユーザー
>神無月サスケさん
コメントのタイミングが悪かったみたいですみません(^▽^;)
私の作ったプラグインでも確かにロード直後にセーブが繰り返されているのが確認できました。
検討していただけるということで、本当にありがとうございます!!
私も自分なりに精一杯調べてみたいと思います…!!
 
どうも。解決しました!
それは、「セーブ判定用スイッチ」を用いることでした。

コードを読んでいただけると分かると思いますが、
パラメータで指定したスイッチIDを「オートセーブ用スイッチ」にすれば
簡単に解決できてしまいました。

おそらく、他の方法もあるでしょう。
問題を解決するにしても、答えは必ずしも一つじゃないところが、
プログラミングの面白いところですね。

ご参考になれば幸いです。

※更新時注:添付ファイルはバグがあったため削除しました。下のトピックのをDLしてください
 
最後に編集:

☆鶴香★

ユーザー
>神無月サスケさん
わー!ありがとうございます!!
スイッチを使うのですね!わかりやすくていいです!!

…でも、これだとプレイ中にセーブを2回やろうとすると2回目は失敗してしまうみたいです(´;ω;`)
ロード後にONになるスイッチみたいなのを作ったらいいのでしょうか?
ロード後の処理とセーブを繰り返される処理のどっちが先に行われるのかが問題ですがどうなんでしょう…?
 
すみません、それ、僕の、ものすごくケアレスミスなバグです:kaosigh:
セーブをした後、オンにしたスイッチをオフにしないといけないのに、
それを忘れていたからこうなってしまいました。
直したこちらをDLしてください。

かなりチェックして、ちゃんと動いたのを確認しましたので、、
多分もうこれ以上ケアレスミスはない......ことを願いたいです。
 

Attachments

最後に編集:

☆鶴香★

ユーザー
>神無月サスケさん
そ、そうかセーブをしたあとにスイッチをOFFにすればいいんですね!!
これで完璧だと思います!!
(プラグインの書き方とかも含めて)とても勉強になりました!
これを参考にしながら、自分のプラグイン作ってみたいと思います!
本当にありがとうございました!!!
 

しぐれん

ユーザー
アイテム個別所持プラグインを作成中です。
ドラクエみたいなアレです。

作っていくと、ツクールのアイテムの仕様の利点・欠点が見えてきますね。
ただ、Scene_ItemBaseの実装が美しくないなあと思いました。
(いくつかの場所で、無駄に同じ関数を呼び出していて効率が悪い。引数にすることで再利用してほしい。)

正直、これを作るのを今にしてよかったと思います。
最初からこれを作ろうとしたら、間違いなく混乱したので。
Window・Item・Scene・Battlerとあらゆるクラスの知識が要求される総合格闘技のような状態です。
セーブするオブジェクトの存在するプラグインというのも一つの壁ですね。

デザインパターンの知識はあると便利だと思いました。
アイテム個別所持プラグインを作成中なのですが、stateパターンで実装することによって複雑な実装が簡単にできそうです。
switch文の排除という場面では、大きな威力を発揮しますね。
アイテムに対して行う処理としては、入れ替え・使う・捨てる・売る・しまうなどなど、際限なく存在します。
(これらをモードと呼んでいます)
また、アイテムポケットにnullが入っている時の挙動もモードごとに異なるので、isItemEnabled()の処理をSceneクラスに格納されているモードオブジェクトに委譲するようにしています。
一週間ぐらいで、完成すればいいなと考えています。
 
最後に編集:

尾角つの

ユーザー
ツクール本体自体のバグ?みたいな挙動をする部分を見つけたのですが、どこに報告すればいいかわからなかったので、とりあえずここに書き込もうかと思います。

バトルのイベントについてで、バトラーの行動後すぐに行うイベントで行動の強制を行うと、強制行動する前に行動していたキャラクターの行動終了後のステート解除が行われない、連続行動を行っている場合それらはキャンセルされる、という症状が出ています。

原因を自分でできる範囲で探したところだと、行動強制時に BattleManager.processForcedAction で、現在行動中のthis._subjectが強制的に上書きされているせいかなと思っています。
強制行動前に、this._subject を this._actionBattlersにunshift する(強制行動後に再度残りのアクションを行う)か、
this._subject の全アクションを終了させる処理(本来 processTurn の action がないときの処理 +α)の処理を入れたらいいのではと思ったのですが……

ここで書き込んだらツクール開発部さんに拾ってもらえるかなと思ったのですが、もっと報告しやすいところあったら教えていただけると助かります。
 

尾角つの

ユーザー
ちょっとわかりづらかったので例を……
1、HPが99%以下になるとエネミーが反撃するイベントを用意(反撃後には全回復する)
2、ステート(行動終了後に回復する)にかかったアクターでエネミーを攻撃。(自然回復するターンです)
3、エネミーが反撃するイベントが行われるが、アクターのステートは回復しない。(アクターの後処理が行われないため)
 
>尾角つのさん、こん**は。
僕の環境でも同じ条件で試してみましたが、
どうやら、敵キャラが複数いる場合、IDの一番若い敵キャラに対してのみ、2回攻撃を行うようですね。
2体目以降は、反撃状態が続いていても、1回しか反撃しないし、
1体目の最初の反撃でアクターの攻撃が当たらなければ2度目の攻撃は行われない。

しかも、書かれている通り、1体目が残っていると、いつまでたっても
解除されるはずの反撃状態が残ってしまうことも確認しました。

……確かにちょっと込み入った問題のようですね。
今からソースコード見ながら確認させていただきます。
僕の手に負えないと判断したら、「無理そうだ」ときちんと返事ます。
 
最後に編集:
>尾角つのさん:
早速、細かくこのあたりの解析をさせていただきました。
※検証コアスクリプトは1.5.0です。

結果、尾角つのさんの想定通り、 BattleManager.processForcedAction でドンピシャでした。
この関数、アクターの反撃後、敵も反撃体制に入ると、先に反撃を行った方の行動強制が行われないことが分かりました。
つまり、最後に反撃を行った敵キャラのみがこの関数を呼び出していました。

要するに、「反撃に対して反撃」というケースで、最初の反撃のことが考慮されていないことによるエラーです。
確かにこれは見つけるのは難しいでしょうね。

これは確かに、ツクール編集部のサポートに連絡した方がいいかもしれません。
 

尾角つの

ユーザー
>神無月サスケ様
細かく見ていただけてありがとうございます!さすがに、早くて驚きです(*'ω'*)
やっぱり、BattleManager.processForcedAction でしたか……

今、自作の戦闘システム作成していて、このあたりの仕様がどうなるかすごく気になるところだったので、Twitterのツクール開発部さんに上記のこと報告だけでもしてみようかと思います。
 

しぐれん

ユーザー
ツクールMVでES2015のクラス構文使ってスクリプトを書いていますが、ブラウザの対応状況どうなんでしょう。
これ使うととても書きやすいので、一度使うと手放せないです。
PCはほぼChromeかEdgeでしょうから対応していますが、スマホ側の事情が把握できません。
古い端末は無視した方が楽なんですけども。
Web出力できるが故の問題ですね。
 

しぐれん

ユーザー
条件分岐などに使う「アイテムを持っているか」の部分を効率よく実装する案が出てこない。
index作るのが最適なんでしょうが、アイテムの増減があった後も整合性が取れているかが不安です。
辛い。
 
トップ