web1week遅刻勢です!
陣取り合戦ロッカッケー
https://rokkakkee.netlify.app
Webブラウザ上で遊べる、ボードゲームのようなルールの自作ゲームです。
コンピュータと対戦する「CPU戦」と、スマホを縦に持ち向かい合って遊べる「対人戦」があります。
基本的なルールを説明します。
【移動】
プレイヤーは自分の隣のマスに移動または攻撃を行い、交互に自分の色の陣地を増やしていきます。
移動するときは、矢印のマスをタップしてください。
【勝敗】
CPU : 2
とかYou : 1
とか書いてあるのは自陣のマスの個数です。
最後までマスが埋まったとき、どちらか多いほうが勝利となります。
Splatoonみたいですね!
【攻撃・防御】
白いマスには移動できますが、相手のマスには移動できません。
代わりに、相手のマスをタップするとそのマスを攻撃します。
マスに書かれた数字は防御の厚さを表していて、攻撃を受けて防御力が下がり0になってしまうと白いマスに戻ります。
逆に、自陣の上を何度も通っていると、防御が厚くなっていきます。
【弱点】
防御があるから大丈夫…なわけではありません。
弱点として、本体を直接攻撃されると、防御力に関係なくマスを奪われる上に、キャラクターがスタート地点に戻されてしまいます。
ただし、相手のスタート地点の隣で攻撃すると、こんな風に逆襲されてしまうことも…。
↓ CPUがスタート地点の隣にいたYouを攻撃し、Youは戻されてしまいました
相手が最後のマスを塗ったため、この時点で面積の多い私が勝ちました。
相手の立場であれば、ここで塗らずにこちらの陣地を攻撃していれば勝てる可能性はありましたね。
正直CPU戦のCPUさんは非常に弱いのですが、ルールを把握して頂くには十分かと思います。
オンラインではありません。対面です。
【先攻】
先攻はランダムに決まります。ちなみに、これはCPU戦でも同じです。
防御力の数字の向きは紫側から見ると逆さまになります。申し訳ないです。
勝敗画面はこんな感じです。
web1weekにゲームエンジン持ち込むのは反則だろうというような気はしないでもないですが、まあWebなら何でもいいだろうということで、国内ではあまり認知度が高くない「GDevelop」というゲームエンジンを使用しました。
元々このゲームの構想自体はずっと温めていて、今回web1weekに便乗して実装することにしたわけですが、1週間で作るとなるとJavaScriptのコードを直接書いてゲームを1から作っていくのはなかなか骨が折れそうだと思いました。
そこでWebに出力できるゲームエンジンを探したのですが、意外とこれが少ないのです。
UnityにもWeb出力機能はありますが、機能制限が色々ある予感がしたのと流石にUnityでweb1weekに参加するのはお門違いだろうという思いがありまして、結局たまたま検索で見かけたGDevelopを採用しました。
GoogleのソフトウェアエンジニアであるFlorian Rival氏が手掛けている、様々なプラットフォーム上で動作するゲームが作れるゲームエンジンです。
2008年から続いているプロジェクトのようですが、未だに高頻度にリリースが続いており、しっかりメンテナンスされている印象を受けます。
操作はGUIで完結していて、コードを書く必要はありません。(これがあまり嬉しくないわけですが)
また、日本語訳が充実しており、ドキュメントも完全に日本語で利用することができます。
原文より日本語訳のほうがまともなんじゃ…と思う瞬間すらあります。
どうやら、株式会社マイティークラフトという会社が日本語訳を担当しているようです。ありがたいことです。
簡単にゲームアプリを作れるゲームアプリ制作ツール「GDevelop」の日本語化とサポートを開始 - 株式会社マイティークラフト
日本語版のドキュメントはこちらです。
GDevelop5を試してみたい方は、このページの「はじめに」、「ゲーム作りの基本コンセプト」、そして「チュートリアル」を見ておくことをおすすめします。
非常にクセがあるので未読で触るとヤケドするかもしれないです…。
正直実装がここまで苦労するとは思っていませんでした。
まだ理解が不十分なところはあるかもしれませんが、仕様レベルでしんどいと感じた点をいくつか挙げてみます。
まず、GDevelop5で言うインスタンスとは何かを説明しますね。
GDev5にはオブジェクトというものがあります。
オブジェクトは「スプライト」「テキスト」など様々な種類があります。
オブジェクト自体にはどのような画像を使うかなどを設定します。
オブジェクトの設定ができたら、オブジェクトを画面上にドラッグアンドドロップすることでインスタンスが画面上に作成され、利用できるようになります。
オブジェクトが利用可能な形になったものが「インスタンス」、と捉えれば一般的な認識の通りでしょう。
画面構成を終えたら、それぞれのオブジェクトがどのように挙動するのか、「イベント」設定画面で設定する必要があります。
つらいのはここからです。
イベントは、「○○だったら△△する」という形式、つまり「条件」と「アクション」がセットになったものを大量に並べることで構成されていきます。
ここで例えば「衝突」などの条件を設定することができるのですが、このとき対象として設定できるのは「オブジェクトの名前」になります。
「インスタンス」ではありません。
これが非常に大きな罠として待ち構えています。
どういうことでしょうか?
例えば、マリオのようなゲームを考えてみましょう。
これは公式チュートリアルに書かれている「プラットフォームゲーム」を実装したものです。
空中にコインが3枚ありますね。
これはCoinというオブジェクトのインスタンスが3つ並んだものです。
このコインを取ったときに、コインが消えるイベントは以下のようになっています。
条件は「Player
はCoin
と衝突している」、アクションは「Coin
を削除する」。
ここで違和感を感じると思うのです。
Coinって、どのコインのこと?
このときの挙動がこちらになります。
(↓GIFが動いていない場合クリックすると動くかもしれません)
ちゃんと取ったコインだけが消えていますね。
では次に、条件を「Player
はCloud
と衝突している」に変えてみます。
Cloudとは、飾りとして置いている雲のオブジェクトのことです。
(↓GIFが動いていない場合クリックすると動くかもしれません)
全部のコインが消えましたね。
ここから分かることは、オブジェクト名を指定しつつ、その参照先インスタンスは文脈によって変化しているということです。
前者のイベントでのCoin
は、「Player
と衝突したインスタンス」でした。
一方、後者のイベントでのCoin
は「全てのインスタンス」になっています。
つまり、オブジェクトを指定したように見せかけていますが、その実態は複雑なインスタンス指定を隠蔽したものだったわけです。
見かけは簡単になっていますが、私はこの挙動が非常に気持ち悪いと感じています。
これに拍車をかけてつらいのが、「インスタンスを個別に指定して参照できない」ということです。えっ…なんで?
普通ゲーム作るときってインスタンスの参照できるように配列にインスタンス突っ込んだりしますよね?
えー配列はまだ扱えません。
というか配列が使えるようになったところでインスタンスの参照は代入できないのでね。えー…。
例えば今回のロッカッケーでは六角形のタイルの表示にBaseTile
というオブジェクトを使用しています。
見た目が変わったり矢印を出したりかなり複雑な挙動をするのですが、イベントの中でどのタイルが参照されているのか全くわかりません。勘ですかね?
基本的に条件があればその条件で使われたインスタンスが、親イベントがあれば親イベントで参照されているインスタンスが使われる気がしますが、正直わからないです。地獄。
インスタンス毎にidが振られて参照できたりするようになればだいぶマシになると思います。改善希望です。(2021/3/8時点)
ちなみにそれまではインスタンス変数にidっぽいものを入れて「インスタンス毎に繰り返し」を使ってインスタンス変数をチェックしていく方法が疑似的に使えると思います。
なんで使いたいたびに繰り返さないといけないんだ…。
コードからゲームを作ったことがある人は分かってもらえると思うのですが、コードから作ると毎フレーム1つの関数の中に書いた処理が全部実行されますよね。
GDevelop5もあのような仕組みで、「イベント」に書かれた内容が毎フレーム実行されます。
これはScratchのようなビジュアルプログラミング言語に親しんでいた人たちにとっては中々慣れないのではないでしょうか。
Scratchの優秀なところは、非同期に書かれたプログラムを逐次実行してくれるところです。
右に行って、1秒待って、左に戻る、なんてScratchなら3行で書けるでしょうが、GDevelop5では地獄のようなものを組まないといけないわけです。
右にアニメーションして移動するなんていうのはTweenビヘイビアというのを使えばまだマシになるのですが、何秒待つというのは本当に面倒です。
待機させる仕組みが無いのです。なんで…??
調べた感じ変数にフレーム数を入れるだとか、シーンタイマーを使うだとか、Tweenで疑似的に待たせるだとか、色々試されているようですが、正直どれもしっくりこないし、しんどいです。
全部つらい。Scratchのほうがずっと簡単で高度なものを作れた気がするよ…。
他にもいろいろ細かい不満がないわけではないですが、仕様レベルでつらいのは大きくこの2つだと思います。
まだ積極的にアップデートが続いているようなので、GDevelop6でも来たらまた触ってみようと思います。
オンライン対戦ができるようにしたいです。
WebSocketの使い方とかも少しずつ覚えてきたので、PixiJSとかと併せて使ったら実装できそうです。
あと今回GDevelopの仕様につまづいて燃焼不良となっている部分が多いので、挑戦も兼ねてUnityとかでも改めて実装してみたいです。
とにかく今回、頭の中で考えて面白いか不安だったものを他の人に面白いと言ってもらえて嬉しかったです。
新しい技術に触れる良いチャンスでもありますね。ありがとうございました。