実際にマルチプレイゲームを考えて作ろう

前ページまでで、Akashic Engine + マルチプレイ なゲームを作るための大雑把な知識を導入し終わりました。 最後に、いままでのおさらいや考え方を軽く流した後に、こちらで用意したサンプルゲームの紹介をしていこうと思います。

いままでのまとめ

今までの連載を1項目につき一行でおさらいします。

  • マルチプレイゲームとはどういうものか
    • 他人が同じ世界に存在し、共有物やお互いに干渉しあうゲーム
  • 他人と自分で違う状態を持つ方法
    • ローカル処理によって自分の PC だけで発生する処理、を記述できます
  • 自分の操作を他人へ伝える方法
    • raiseEvent によって、任意の情報を全員に送信することができます
  • ニコ生上で動作させるための tips
    • ゲーム起動直後の Join 処理によって、放送者を識別することができます

かなりの超特急にも感じますが、仕組みの解説は殆ど終わっています。 今回紹介するサンプルゲームも、今まで連載に出て来た以上のことはしていません。

実際にゲーム作る

実際のゲームの中身は皆さんに考えていただくとして、以上の知識があれば理論上はマルチプレイゲームが作れます。 したがって以下では、技術の話というよりはサンプルゲームを紹介しつつ、どのような流れで作り、何を気をつけたか、といった大まかな流れの部分を説明していこうと思います。

ゲームを考えた

一番最初の記事に遡って、どんなゲームを作るか考えます。こういう時のコツは、目標や条件など定義して自らに制約を課すことです。 今回は以下の制約を設定しました。

  • ニコ生上で投稿ゲームとして動作させること(運営だけが使える機能みたいなのは使わない)
  • PC、スマホ両方で遊べること
    • スマホ対応、という点からキーボードとマウスに依存しないこと
    • PC 対応、という点からマルチタッチに依存しないこと
    • 以上より、指一本で遊べ、精密なタッチを要求しないこと
      • 小さいマス目を正確にタッチする、みたいなのはスマホではキツイ
      • 綺麗な直線を素早く書く、みたいなのはマウスではキツイ
  • 放送者を含む参加者全員のガチンコ勝負で、最後に一人だけ勝者が決まること
  • 画面上に他人が存在すること
  • 複雑なルールを要求しないこと

こんな感じで設定しました。 最近のニコ生ではタワーが流行っています。少し前はつりっくまやだるまさんがホットでしたね。 タワーは協力ゲーム、だるまさんは放送者 vs 他全員、つりっくまは個人戦だけど他人の様子がよくわからない、という特徴を持っていました。 今回はそれのいずれとも性質の異なるゲームを作りたくて前述の制約となりました。

JumperGame

岩を避けながらジャンプし、少しずつ右へ進んでいくゲームを作りました。 最大30人まで参加することができます。見た目はなんともですが

  • 放送者をゲームマスターとした参加、募集締め切り
  • 参加者全員で同期したゲーム進行
  • 自分のジャンプを全員に通知し同期させる

といった、マルチプレイゲームに必要な要素はだいたい入っていると思います。

ソースコード一式は以下で入手できます。 https://github.com/akashic-contents/jumper-game

ゲームの流れ

  1. ゲームが起動されると誰かの join を一回だけ待つ
  2. join して来た人をゲームマスターとして設定
  3. タイトル画面で参加者待ち受け開始
  4. ゲームマスターが適当なタイミングでゲーム開始
  5. ゲーム画面で遊ぶ
  6. 終了条件を満たしたら終わり
  7. 3 に戻る

これを繰り返します。以下で個別に解説していきます。ゲームマスターや Join については第3回の記事が理解に役立つでしょう。

ゲームマスターの Join 待ち

ゲーム起動直後のコードがこんな感じです。

function onJoin(e) {
  // e.player.idを使って初期化処理
}

g.game.join.addOnce(e => {
  onJoin(e);
});

// joinを待ち受ける仮のシーン
const dummyScene = new g.Scene({ game: g.game });
dummyScene.update.add(() => {});

g.game.pushScene(new g.Scene({ game: g.game }));

Akashic Engine の仕組み上での Join を待ちます。ニコ生ではゲーム起動時に放送者のみが Join する、という仕組みになっていますので実際にはほぼ一瞬かと思います。

タイトル画面

タイトル画面の中身は解説記事第三回の中身ほぼそのままです。 ボタンを二つ初期化し、ゲームマスターには参加締め切りボタン、それ以外の人には参加ボタンを表示しています。

それぞれのボタンはローカルエンティティとなっていて

  • 開始ボタン:close メッセージを全員に送り、募集を終了する
  • 参加ボタン:join メッセージを送り、募集に参加する

という機能を持ちます。ここでいう join は Akashic Engine の Join とは関係ない、このゲーム独自の処理です。

ゲーム画面

ゲームが開始されると、もし参加していればボタンが二つ表示され、自分のキャラ(Jumper)が赤くハイライトされます。 ここで重要なのは、何がローカルで何がグローバルなのかを考えることです。 Akashic Engine では特筆しない限りグローバルとなるので、この画面に存在するもののほとんどはグローバルであり、ローカルなものを抽出したほうが早いでしょう。

と言いつつ、ローカルなものは殆どありません。 敵の配置やラウンド進行、残り人数や順位といった、ほぼ全ての情報は同期してほしいためグローバルになっています。 ローカルな分岐で破壊しないことに気をつけて書くだけで、全ての操作が同期するのは結構すごいことです。Akashic Engine の強みです。

一応以下に、意識してローカルエンティティを書いた部分をあげておきます。

今回のゲームでローカルなもの

ボタン

まず、左下と右下にあるボタンは操作用のもので、これを押すと Jumper がジャンプしたり、挨拶したりします。 自分がジャンプボタンを押した時、自分の Jumper だけがジャンプしなければなりません。

これを実現する方法は二つあります。

  1. ボタンが押された時の処理で誰が押したかを判定し、そのキャラだけをジャンプさせる
  2. ボタンをローカルエンティティとして作り、メッセージを送信してそのメッセージでジャンプさせる

どちらでも実現できます。1 のほうが処理が簡単なのですが追加条件として

a. ジャンプした後はしばらくボタンが押せない b. ジャンプできない場合、ボタンがグレーになる

をつけると話が変わってきます。a だけであればまだ 1 でも大丈夫でしたが、ボタンそのものの状態を各々変えるにはボタンをローカルエンティティにする必要があります。 そうするとボタンが押された時の処理にはグローバルなものが書けないため、2 の手法を取る必要があります。挨拶ボタンに関しても同様です。

Jumper

Jumper の画像もローカルエンティティです。 Jumper の位置、生死、ジャンプしているかどうかなどといった情報は全てグローバルなものですが、自分の Jumper は強調表示されてほしいため、Sprite はローカルエンティティで作ります。

制作を進めていく上での注意点

raiseEvent の取り扱い

実際にゲームを作っていくとすぐにわかることなのですが、raiseEvent を使わなければならないシーンはかなり少ないです。 状態は何もしなくても他人と同期するという Akashic Engine の特徴があるためです。 同期していないもの、つまり他人が知り得ない情報が同期状態にあるものに影響を及ぼすとき初めて、raiseEvent の出番になります。 大体において、これは誰かがローカルなエンティティを操作した時が該当します。 自分だけの操作は他の人は知り得ないので、操作した結果を通知する必要があるわけですね。

まとめ

今回は今までのおさらいを軽くしつつ、いままでのまとめとして作ったマルチプレイゲームを掲載しました。 マルチプレイゲームの作成に基本的な知識は解説し終わりましたので、ここで一旦この記事は一区切りとなります。 ニコ生上でマルチプレイゲームを作るという試みは一見荒唐無稽ですが、ニコ生での新しい遊び方の一つとして今後も進めていきたいと考えています。 現時点でも、ニコ生上でゲームを動作させると以下のようなメリットがあります。

  • サーバーを用意せず公開できる(生放送にきてもらう必要がありますが)
  • ログイン機構がいらない(ニコニコにログインしないとゲームが操作できない)
  • タイムシフトに対応する(Akashic Engine の機能でプレー内容が保存される)

まだまだ機能が少なかったり、解説できていない機能もあったりしますが、この記事が少しでもニコ生ゲーム投稿の助けになれば幸いです。