Skip to content

Instantly share code, notes, and snippets.

@shpqg
Last active March 13, 2020 14:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shpqg/cd4ec43645ec31113bc42f685d5d223d to your computer and use it in GitHub Desktop.
Save shpqg/cd4ec43645ec31113bc42f685d5d223d to your computer and use it in GitHub Desktop.

extensionsを用いたJS拡張について

こちらはスーパー正男Re同盟 年越しカレンダー 2019-2020の7日目(12/30)の記事です。年越しカレンダー 2019-2020 バナー

正男のuserJSCallbackを入れるオブジェクトがあると思うんですが、あれにextensionsなるものを足すことでMasaoJSSを経由するよりもさらに正男の内部を制御できます。例えばかの有名なMasaoSpaceなる正男投稿サイトにもあるリプレイ機能はこれを利用して作られているような気がしています。

今回はこれを利用することで、現在のMasaoJSSでは難しいJS拡張をいくつか可能にしていこうと思います。

追加すべきコード

実装方式は色々ありそうですが、今回は一応お行儀よく(?)MasaoJSSを拡張する形で行います。例えばこのような感じで:

new CanvasMasao.Game({
  // params
}, null, {
  extensions: [(()=>{
    function MyMasaoJSS(mc, apc) {
      apc.apply(this, arguments);
      // 追加したいメソッド
      // 例:ファイヤーボールを装備しているか
      this.isEquipFire = function () { return mc.mp.j_fire_f };
      // 以下,個人的に使うだけのためMasaoJSSのメソッドほど安全性を考慮しないことに注意してください
      // 例えばMasaoJSSではまずmc.mpが本当に存在するかを確かめることが慣例です
    }
    return {
      inject: function(mc, options) {
        const _ui = mc.userInit,
              _us = mc.userSub;
        mc.userInit = function() {
          _ui.apply(mc);
          const apc = this.masaoJSSAppletEmulator;
          mc.masaoJSSAppletEmulator = new MyMasaoJSS(this, apc.constructor);
        };
        mc.userSub = function(g, image) {
          _us.call(mc, g, image);
        }
      },
    };
  })()],
  userJSCallback: // ...
})

追加したいメソッドの例でmcを参照していることがわかるかと思います。これはCanvasMasaoのソースコードではMasaoConstruction.jsにあたります(GitHub上のURL)。mc.mpMainProgram.jsであり、これが正男や敵や敵の弾など、ゲーム性にかかわる部分を管理している部分です(おそらく)。

なお本筋とは関係ありませんがメソッド追加以外の部分が何をしているのか雑に説明しておきます。GlobalFunction.jsにあるように、正男を起動する際に作られたMasaoConstructionは、配列extensionsに入った各オブジェクトのinjectメソッドに渡されます。これによりinject内部からMasaoConstruction、およびそれが持つMainProgramMasaoJSSオブジェクト(masaoJSSAppletEmulator)を触ることができ、好きなメソッドをMasaoJSSに生やせるという寸法です。

改造例1: 死ぬと復活

まずはちょっとした例から:サンプルステージ。ソースをここに貼ると長くなるため、サンプルステージから見てください。現在のMasaoJSSではgetMyObjectConditionという正男の状態を取得するメソッドは実装されていますが、状態を指定するメソッドはありません。これを実装し、正男が死亡したとき、すなわち正男の状態が200以上250以下の範囲内になったときに通常の正男の状態(=100)を代入することで、正男を生き返らせることができます。

正男を表すオブジェクトはmc.mp.co_jに格納されており、正男の状態はmc.mp.co_j.cです(どのフィールドがどれであるかはCharacterObject.jsを参照するとわかる……かもしれません)。したがってここに引数として与えられる数値を代入するメソッドを実装すれば実現可能です:

this.setMyObjectCondition = function(c) { if(mc.mp) mc.mp.co_j.c = c };

改造例1': ボスを踏んだときの正男の挙動を再現する

これは今回の主題からは少し外れた雑学的な話です。setMyPress(3)を使えばよいと思われるかもしれませんが、実はこれはあまり正確ではありません。実際のゲーム内でボスを踏んだ際はmc.mp.co_j.c1-4となっているのですが、setMyPress(3)そうしていないために踏んだ後のタメの時間が異なるからです。よって、

this.setMyPressBoss = function() { this.setMyPress(3); mc.mp.co_j.c1 = -4 };

を使うと実際の挙動に近づきます(サンプルステージ)(左がsetMyPress(3)、中央がsetMyPressBoss())。もっともこの件については標準のMasaoJSSに追加するPull Requestを出してもよいのかもしれませんが面倒なので誰かやってください

改造例2: ファイヤーボールを跳ね返す壁

こちらのサンプルステージのソースを参照してください。正男の放つ弾系オブジェクト(ファイヤーボールやグレネード)について位置や速度を取得し、壁に当たる場合に速度を反転させることで反射を実現させています。これらはmc.mp.co_jmという配列に入っており(実はこれはあまり裏を取っていないのですが)、これについて色々と情報を取得したり、反映させたりするメソッドを実装すればよいです:

this.getFireballObjectCondition = function(i) { return mc.mp.co_jm[i].c  };
this.getFireballObjectPattern   = function(i) { return mc.mp.co_jm[i].pt };
this.getFireballObjectX  = function(i) { return mc.mp.co_jm[i].x  };
this.getFireballObjectY  = function(i) { return mc.mp.co_jm[i].y  };
this.getFireballObjectVX = function(i) { return mc.mp.co_jm[i].vx };
this.getFireballObjectVY = function(i) { return mc.mp.co_jm[i].vy };
this.getFireballObjectLength = function() { return mc.mp.co_jm.length };
this.setFireballObjectX  = function(i, v) { mc.mp.co_jm[i].x  = v };
this.setFireballObjectY  = function(i, v) { mc.mp.co_jm[i].y  = v };
this.setFireballObjectVX = function(i, v) { mc.mp.co_jm[i].vx = v };
this.setFireballObjectVY = function(i, v) { mc.mp.co_jm[i].vy = v };
this.setFireballObjectCondition = function(i, v){ mc.mp.co_jm[i].c = v };

ちなみに似たような用例として、ファイアーボールがある位置を光らせるというスポット処理も挙げられそうです。敵弾についても同様のメソッドを実装することで、ピカチーの電撃やエアームズの爆風なども光らせることが可能です。extensionを通さない汚い実装ではあるものの、過去にこの考え方で作ったスポットを使ったステージがこちら(そこまでお薦めできません)。

まとめ

このような感じで実際にCanvasまさおのソースを読む必要がありますが、より幅の広い改造ができます。Canvasまさおも開発にかかわっているみなさんのおかげで昔より格段に読みやすくなったこともありますので、一度見てみてはいかがでしょうか。また既に触れたMasaoSpaceでおなじみのうひょ氏は今回取り上げたMainProgram以外のもの、例えばキー入力を管理するGameKeyなどを操作する正男も公開されており、参考になるかと思います。

ただしCanvasまさおのソースコードが更新された際はもしかしたら使えなくなる可能性もありますので、そのあたりは注意が必要かもしれません。あと私はCanvasまさおのリポジトリについて何の権限も持っていないので何とも言えないんですが、MasaoJSSに標準で追加してもよさそうなものがあったらPull Requestを送ってもよいのかもしれません。

すべてのサンプルステージのextensionsおよびuserJSCallback部は著作者表示やリンクなしでご自由に利用して構いません。紹介したネタもお気兼ねなくお使いください(そのために書いたので)。それ以外のもの、例えば画像や非サンプルステージのデータなどについては遠慮してください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment