Akashic Engine の RPG アツマール連携 Tips

この文章は、 [Akashic Engine Advent Calendar 2019](https://qiita.com/advent-calendar/2019/akashic-engine) の 10 日目です。

# Akashic Engine と RPG アツマール

[Akashic Engine](https://akashic-games.github.io/) は、ニコニコ生放送上で配信者と視聴者が遊べるゲーム、いわゆる [ニコ生ゲーム](https://site.live.nicovideo.jp/ichiba.html) の作成に利用できます。作成したニコ生ゲーム (ニコニコ新市場対応コンテンツ) の登録は、

1. HTML5 ゲーム投稿サイト [RPGアツマール](https://game.nicovideo.jp/atsumaru/) に投稿し、
2. そこからニコニコ新市場に「登録申請」する

というステップで [行われます](https://akashic-games.github.io/guide/shin-ichiba/index.html) 。そのためニコ生ゲームは、特に非公開にしなければ自動的に RPG アツマール上でも遊べるものになります。公式が投稿しているものだと『[ゴミをゴミ箱に入れるだけのゲーム](https://game.nicovideo.jp/atsumaru/games/gm8598)』 なんかがあります。

![スクリーンショット 2019-12-10 21.16.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540286/6332223e-2570-ba73-8e3c-d1334d125c6c.png)


RPG アツマールにはゲーム投稿サイトとしていろいろな機能がありますが、Akashic Engine には特段それを意識したツールサポートはまだまだないのが現状です。そのため、普通にニコ生ゲームを作成して投稿すると、 RPG アツマールでは少々「浮く」部分が出てきてしまいます。

そこでここでは、Akashic Engine を RPG アツマール上で動かす時の細かな Tips をいくつかご紹介します。


## アツマールでのみ背景色をつける

ニコニコ生放送上で実行される場合、ゲーム画面は配信に重なって表示されます。

そのため画面の一部を透明や半透明にしたいことがよくあります。しかし同じゲームが RPG アツマールで実行される時は、後ろに配信画面は当然ないので、この透明部分は真っ黒になってしまいます。PRG アツマールでは投稿時にゲーム画面の「枠外」の色を選べますが、これはゲーム画面の部分には適用されません。

この問題は、 `akashic export html` コマンドのオプション `--inject` を使うことで回避できます。

`--inject <filepath>` は、出力される HTML の `head` 要素の末尾に `<filepath>` のファイルの内容を書き込むオプションです。この HTML は、アツマール (や Web サーバに置いた時) でのみ利用され、ニコニコ生放送上では使われません。

そこで次のような内容のテキストファイル `injectdata.txt` を準備します。

```html
<style>
body {
  background: silver;
}
</style>
```

export html コマンドを次のように実行すると、

```shell
akashic export html --atsumaru -o ./game.zip --inject ./injectdata.txt
```

生成される HTML にはこの `style` 要素が含まれるため、アツマール上では透明部分が灰色になります。 `background` の色だけ指定していますが、要するに単なる HTML/CSS なので、任意の記述ができます。

## アツマールでのみ特定の動作を行う

たとえば「RPG アツマール上でのみ "もう一度プレイ" ボタンを出す」など。

ニコニコ生放送の、特にランキング形式のゲームは「一度起動して時間いっぱいプレイ→結果発表して終了」というフローを辿ります。しかし RPG アツマール上で同じゲームを遊ぶ場合は、単にもう一度プレイするボタンが欲しくなることがあります。

"もう一度プレイ" ボタン自体は、Akashic Engine で普通に作成すればよいはずです (ゲームの内部状態を初期状態にリセットしまくる処理になるでしょう)。

問題はそのボタンを「RPGアツマールでのみ」表示することですが、別に難しいことはありません。RPG アツマール環境では、アツマール独自の機能を提供する変数 `RPGAtsumaru` が存在します。この変数の存在をチェックをすれば、コンテンツが RPG アツマール上で実行されているかを判定できます。

```javascript
if (typeof window !== "undefined" && window.RPGAtsumaru) {
  // RPG アツマール上でのみ実行されるコード

  var returnToStartButton = new Sprite({  // 最初に戻るボタン
    // ...
  });
  scene.append(returnToStartButton);
}
```

まあ、見たまんまですね。

一点だけ、 Akashic Engine のコンテンツは必ずしもブラウザ環境で実行されているとは限らないため、 `window` がないかもしれないことに気をつけてください。存在チェックは `typeof window` から始める必要があります。

なおゲームを以下のコマンドで生成した、いわゆる「新市場ランキング対応コンテンツテンプレート」の場合は、

```shell
akashic init -t javascript-shin-ichiba-ranking
```

`main()` の引数 `param` に `param.isAtsumaru` がついています。アツマール環境でのみ `true` になっているので、これを利用することもできます。


## アツマールのスコアボードに対応する

ランキング対応ゲームの場合、ゲーム中ではスコアがあります。RPG アツマールにもハイスコアを記録してランキング形式で表示してくれる「スコアボード」機能がありますが、両者はそのままでは連動してくれません。

これはゲーム部分が終わってスコアが確定した時点で、次のコードを実行することで対応できます。

```javascript
if (typeof window !== "undefined" && window.RPGAtsumaru) {
  var scoreboards = window.RPGAtsumaru.experimental.scoreboards;
  scoreboards.setRecord(1, g.game.vars.gameState.score).then(function () {
    scoreboards.display(1);
  });
}
```

`setRecord()` でスコアを記録し、 `.then()` で書き込みの完了を待ってから `display()` でスコアボードを画面に表示させます。`setRecord()` と `display()` の `1` はスコアボード ID で、両方で同じ値なら 1 から 10 までどれでも構いません。(おそらく複数のランキングのスコアボードを作るための機能ですが、ニコ生ゲームのスコアは一種類しかないので 1 だけ使えば済みます)

……と書きましたが、実はこのコードは `akashic init -t javascript-shin-ichiba-ranking` で生成したゲームには最初から書き込まれています。

もちろんこのコード自体は一例で、「ボタンを押したらスコアボードが表示される」などの実装も可能でしょう。ただし `.then()` に渡した関数が呼ばれるまでは、 `setRecord()` の呼び出しが反映されていない可能性があるので注意してください。このへんの仕組みに明るくない方は "JavaScript Promise" とかでぐぐってください……。

## アツマールのスクリーンショットシェア機能を使えるようにする

RPG アツマールの実験的な API に、ゲーム画面のスクリーンショットを Twitter でシェアする機能があります。このスクリーンショット機能は RPG ツクール MV のゲームなら自動的に対応されていますが、Akashic Engine の場合は自力でスクショを作ってあげる必要があります。

これは次のコードで実現できます。(ゲーム冒頭で一度実行するだけで動作します)

```javascript
if (typeof window !== "undefined" && window.RPGAtsumaru) {
  window.RPGAtsumaru.experimental.screenshot.setScreenshotHandler(function () {
    const pngData = document.getElementsByTagName("canvas")[0].toDataURL("image/png");
    return Promise.resolve(pngData);
  });
}
```

ブラウザ環境での Akahsic Engine は canvas 要素に描いていること、またその canvas が一つしかないことに当て込んで、無理やりゲーム画面の canvas を取得して PNG にしています。まったく **公式の API ではない** ので、将来の互換性の保証は全然ないのですが、他に方法がなく……。

`g.Util.createSpriteFromE()` で作成した `g.Sprite` の `surface` プロパティから内部データを引っこ抜けば「ゲーム画面の一部」だけスクショにできるなど、関連する小ネタは他にもありますが、いずれにせよ現時点では Akashic Engine の公開 API の外側を触らざるを得ません。

## まとめ

RPG アツマールでの見栄えを良くする Tips をご紹介しました。

アツマールは [API リファレンス](https://atsumaru.github.io/api-references/) を眺めるといろいろな機能があって、本当はボリューム調整やコメントもある程度制御できるはずです。現状では公式の API 外の動作に依存せねばならないことも含めて、将来的には akashic-cli が自動的にうまいことしてくれるようにしたいですね……。