はじめに
この記事は ドワンゴ Advent Calender 2019の記事です。
ニコ生では現在、ニコ生上で遊べるゲームについて、RPGアツマールを経由したユーザー投稿を受け付けており、自分が作ったゲームをニコ生上で動作させることができます。
さらっと言いましたが、今のニコ生はなんか自分の書いたスクリプトが動かせるんです。
単純な押しボタンのようなものから、配信者と視聴者でバトルするマルチプレイゲームまで、なんか割と作れます。
そこで今回はニコ生ゲーム普及の一環として、表題の通りすごく簡単なマルチプレイゲームを最小最速で作り、Akashic Engineを使うといかに同期処理が楽であるかを示したいと思います。
前提知識
ニコ生上でゲームを動作させるには、現状では弊社で開発しているjs向けフレームワーク、Akashic Engineを利用する必要があります。
https://akashic-games.github.io/
資料
マルチプレイゲームを作る方法について、過去に連載形式で数ヶ月かけて紹介していました。これを読むと作れるようになります。ほんとです。書いた本人がいうので間違いありません。
作りたくなった場合には以下の記事が参考になります。兎角亀毛作ってドンドン投稿してください。
- 第一回: マルチプレイゲームを知ろう
- 第二回: 簡単なゲームを作ってローカル処理に触れよう
- 第三回: JoinとLeaveとニコ生の話
- 第四回: 実際にゲームを考えて作ろう
作成開始
ただいまの時刻は20:52です。なるべく早くできるように頑張ります。
ゲームを考える
考えるところから入ります。今回作るゲームはマルチプレイゲーム、つまり複数人参加型のゲームとなっています。
この辺の定義については、前述の資料第一回にて少し考えました。
直近ニコ生で話題になったマルチプレイゲームとして、全員協力型ゲーム、塔伸ばしことニコニコタワーがありましたが、個人的にはもっとサツバツとしてほしいため
- 全員参加型
- 全員でバトル
- 最終的に順位が定まる
という要素を盛り込みます。といっても最小最速を自負する以上、ゲーム性はお察しください。
考えたゲーム
- 画面に表示されるボタンを最初に押した人だけにスコアが入る
- これをゲーム終了まで繰り返し、スコアが一番高い人が勝ち
簡単ですね。スコアの管理、ボタンのイベントハンドリング、画像の表示、同期が実装できればいけそうです。
素材を作る
お絵かきツールで画像を書きます。急ぎます。マウスがないので丸を書くのが難しいです。
開発環境やプロジェクトを整える
必要ライブラリのインストール
公式の入門記事に則り、必要なコマンド群をnpm iしていきます。
$ npm install -g @akashic/akashic-cli
$ npm install -g @akashic/akashic-sandbox
akashic-sandboxは主に動作確認に使います。
プロジェクトを作る
適当なディレクトリにてakashic initコマンドを実行するとテンプレプロジェクトが作られて捗ります。TypeScriptで書きたいため以下のコマンドを叩きます。
$ akashic init -t typescript
# 中略
prompt: width: (320) 640
prompt: height: (320) 360
prompt: fps: (30)
Now your new Akashic game has been generated. To run with akashic-sandbox:
$ npm install
$ npm run build
$ npm start
See README.md (in Japanese) for more detail and make your Akashic game!
INFO: Done!
プロジェクトについていくつか質問をされます。ニコ生上でゲームを動作させる場合、16:9の比率でゲームを作ることを強く推奨します。別に無視してもいいのですがいい感じに引き伸ばされて16:9に収まるようにして実行されます。
空プロジェクトができたらその中でnpm i すれば、必要なものは一通り入ってきます。利用しないサンプル素材が同梱されているので以下のコマンドで消しておいてください
$ rm -rf audio/*
$ rm -rf image/*
画面にボタンを表示してイベントハンドラを書く
画像読み込みの準備
まずはここからです。ハローワールド代わりに画像を出して押しましょう。画像を出すために、プロジェクトのimageフォルダに描いた画像を叩き込んでおきます。
その後、scanコマンドを叩いて画像の情報をgame.jsonに取り込んでおく必要があります。
$ akashic scan asset
INFO: Removed the declaration for 'se' (audio/se). The correspondig files to the path are not found.
INFO: Removed the declaration for 'player' (image/player.png). The correspondig files to the path are not found.
INFO: Removed the declaration for 'shot' (image/shot.png). The correspondig files to the path are not found.
INFO: Added/updated the declaration for button (image/button.png)
INFO: Added/updated the declaration for button2 (image/button2.png)
INFO: Done!
さっき消した素材情報が消えて、代わりに叩き込んだ画像が追加されました。Akashic Engineの都合として、読み込む画像の縦横比や音声ファイルの長さなどを事前に知っておく必要があるため、この作業は素材が変更されるたびに必要です。
シーンの初期化と記述
Akashic Engineでは「シーン」と呼ばれる纏まりに対して素材やイベントなどを紐づけて扱います。余談ですが、enchant.jsやphaser.jsのようなメジャーっぽいゲームエンジンでも似たような感じです。
シーンで使う素材類は、シーンをnewした時にロードが開始され、loadedイベント発火で利用できるようになるので、以下のようなコードが画像を出すシーンの最小構成になります。
scene.loaded.add(() => {
const darkButton = new g.Sprite({
scene: scene,
src: scene.assets["button"],
touchable: true
});
scene.append(darkButton);
darkButton.pointDown.add((e) => {
// 誰かによってボタンが押されるとここが実行される
});
});
これをものすごく伸ばしていくことでゲームを作っていきます。ひとまずボタンの処理と、マルチプレイ時の同期処理だけ書いてみましょう。先ほどのsceneのloadedハンドラに追記して行きます。
scene.loaded.add(() => {
const font = new g.DynamicFont({game: g.game, fontFamily: g.FontFamily.Serif, fontColor: "black", size: 32});
// スコア表示TOP5用のラベル
const rankingScoreLabels = initializeRankingLabels(scene, font);
const darkButton = new g.Sprite({
scene: scene,
src: scene.assets["button"],
touchable: true
});
scene.append(darkButton);
darkButton.pointDown.add((e) => {
// 押した人を取得
const winnerId = e.player.id.slice(-5);
// scoreを加算する
if (scoreTable[winnerId] == null) {
scoreTable[winnerId] = 1;
} else {
scoreTable[winnerId] += 1;
}
// ラベル更新
updateRankingLabels(scoreTable, rankingScoreLabels);
});
});
g.game.pushScene(scene);
こんな感じになりました。マルチプレイゲームの動作確認は、buildからのserveです。
$ npm run build
$ akashic serve
デフォルトではlocalhost:3300でサーバーが立ち上がるので、ブラウザでアクセスしてみてください。複数窓ひらけば複数人プレイしているのと同じ状況を作れます。
このような感じで、左側のボタンを押すと自分のスコアが加算され、上位5名が表示される、という挙動が実現できました。
このあたりでおや? と思った方がいるかもしれませんが、sceneのハンドラ内では特に何も書いていないのに複数の窓で勝手に状態が同期していることがわかると思います。
これがAkashic Engineでマルチプレイゲームを作る際の最大の特徴で、何も考えずに作るとまるっと同期されます。
何も考えずに書いていくと複数人で触れるボタンが出来上がるわけです。
もう少し書くと、誰かがブラウザでボタンを押すと、その時のpointDownイベントが押した人も含めて同じタイミングで実行されます。
メインループのタイミングとイベントと乱数のシードがAkashic Engineによって勝手に同期することにより、全員の環境で同じ挙動が再現される = 同期される、というワケです。
ニコ生に登録する準備をする
完成品はこちらです。
https://github.com/orzngo/minimum-multiplay-game
ゲームとしての出来はひどい(ほんとはもうちょっと作りたかったけど時間がない。。。)ですが、何はともあれマルチプレイゲームと呼べるべきものは出来たため、ニコ生で動かしましょう。公式ドキュメントを参考にgame.jsonを編集します。
具体的にはenviromentを以下のようにしておきます。
"environment": {
"sandbox-runtime": "2",
"niconico": {
"supportedModes":["multi"]
}
}
出来たらRPGアツマール投稿用のzipを出力します。
$ akashic export html --output button.zip --atsumaru
出来上がったゲームをRPGアツマールに投稿します。このあたりでニコニコのアカウントが必要になるため、持っていない方は今すぐ登録しましょう!
なんかこんな感じになります。アツマール上でも遊べるようにゲームを作ればいいのですが、マルチプレイゲームを作ると多くの場合アツマールでまともに動かないため、限定公開した方がみんな幸せになると思います。
ニコ生に登録してニコ生上で動かす!
で、この状態で右下のその他メニューから、市場に登録申請すれば完了です。まもなくニコニコ新市場で利用できるようになるでしょう。
こんな感じで、ニコ生の右側に表示される、ニコニコ新市場自作ゲームタブに登録されました。だいたい1分以内に登録されると思います。
これでニコ生上で動くようになりました。一般公開されているため、どの番組でもゲームが動作可能です。利用するか否かを最終決定できるのは配信者なので、ダイレクトマーケティングしまくりましょう!
終わりに
なんとか時間いっぱい、ニコニコ新市場の登録まで終わりました。
本当は音を鳴らしたりする予定だったのですが、予想以上に時間がかかってしまい、マジの最小構成になってしまいました。終了条件もないため、ゲームとしての価値はほぼ無ですね……
とはいえ僕が一番言いたかった、Akashic Engineでなんも考えずに作ると全部他人と同期する、ということについては示せた気がしています。
将棋みたいな全情報公開ゲームはこれだけで作れますが、放送者と視聴者でロールを分けて対戦する、みたいなゲームはこの記事だけでは難しいかもしれません。資料として貼った連載記事を読んでいただければと思います(ダイマ)
[PR]
企画として自作ゲームコンテストというものをやっています。
https://ch.nicovideo.jp/shin-ichiba/blomaga/ar1768903
マルチプレイゲームを作っている人はまだ少なく、入賞できる可能性が高いです。作ろう!