Unity 1 Week Game Jam お題 「当てる」

今回も参加しました

Alt text

今回も参加させてもらいました。
今回は反省すべき点が多くある(期日から1週間遅れた)ので、レポートを書いていきます。

作ったゲーム「BountyBommer」

Alt text

↑画像クリックでプレイできます。
爆弾を武器に戦う主人公が、マフィアに選挙された街を救うけど、
爆弾の取扱に失敗すると逆に街を破壊して賠償金を請求されると言うゲームです。 (過去にゲームセンターにあった、リアルドライブライクなゲーム)

1週目 月曜〜水曜

この時期はずっと企画を考えていました。
今回の企画は、個人的に考えやすそうだけど、色んな案を考えていると大体似たり寄ったりな着地点に行き着いてしまい、難易度が高かったです。
幾ら考えてもよくありそうな企画に行き着いてしまい、考えては消してを繰り返しました。

以下は実際に企画を考えてた際のマインドマップ

f:id:project-unknown:20180304035903p:plain

1週目 木曜〜土曜

建物が爆破された際の表現をどうするか考えたのですが、以下のAssetを採用しました。

このAssetはSpriteを簡単に細切れに破壊する表現を行うことが出来る為、今回のゲームには打ってつけのAssetです。

詳細な使い方はまた別途纏めようと思うので、どんなイメージで作るのかをサマリますが、

f:id:project-unknown:20180304113707p:plain

Inspector上で、爆破の範囲や細切れにするフラグメント等の見た目の制御を行い、
例えば、以下のコードをGameObjectとしてScene上に配置してあげれば、Scene上のSpriteはどんなものでも破壊できます。

public class SpriteExplode : MonoBehaviour {
    private Exploder2DObject _Exploder;

    void Start () {
        _Exploder = Exploder2D.Utils.Exploder2DSingleton.Exploder2DInstance;
    }

    public void ExplodeObject(GameObject obj) {

        var explodeObject = obj.GetComponent<SelfExplode>();
        if (explodeObject != null) {
            explodeObject.ExplodeObject();
        }
        _Exploder.transform.position = Exploder2DUtils.GetCentroid(obj);

        _Exploder.Radius = 0.1f;

        // DONE!
#if ENABLE_CRACK_AND_EXPLODE
        _Exploder.Crack(OnCracked);
#else
        _Exploder.Explode(OnExplosion);


#endif
    }

    /// 爆破完了後に呼ばれるコールバック
    void OnExplosion(float time, Exploder2DObject.ExplosionState state) {
        if (state == Exploder2DObject.ExplosionState.ExplosionFinished) {
            // Debug.Log("finish!");
        }
    }
}

※爆破の挙動はInspectorだけではなく、コード上からも柔軟に変更できます。

ただ、このAssetは1つだけ使いにくい所があって、このAssetのオブジェクトはシングルトン設計になっているため、複数Objectを指定した所で結局同じところで処理されてしまいます。
これが何を意味するのかと言うと、2D開発時にLayerを用いて奥行きや段差を意識する設計で作ってしまうと、Exploderが作用するLayerを切り替えて実装する事になるのですが、爆破解体されたSpriteまでExploderのLayerを引き継いでしまうため、挙動がおかしくなります。

今回のゲームでは最前面のLayerにだけExploderを作用させ、後ろのLayerはExploderを使わない方向で対応しています。

とまぁ、Exploder2Dの使い方に苦戦しつつも、1週目の土曜にはある程度ゲームとして形になる所までは完成していました。

1週目 日曜

通しでプレイした際に、ゲーム2週目で以下のErrorが出まくる事態に遭遇しました。

MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.

エラーログそのままなのですが、2週目でとあるGameObjectにアクセスしようとした際に、既に開放されたGameObjectにアクセスしようとしてエラーが発生しています。
この不具合が本当に厄介で、別なオブジェクトからアクセスする時のみ発生して、例えば自分のライフサイクル(StartやUpdateメソッド)でアクセスすると、問題なく値が入っている事。
となると、古い参照が残ってしまっているのかと思われるのですが、その参照を残してしまっている所が具体的に分からず、
また、この不具合の質が悪い所は、WebGLの場合、ブラウザリロードしても参照を維持してしまう事です。

似たような所で、以下でも語られていましたがどれも効果はありませんでした。

answers.unity.com

answers.unity.com

answers.unity.com

stackoverflow.com

この日はほぼ、この不具合の調査を行っていたのですが、解決することが出来ず、締め切りの20時に。
まさか間に合わないと思っていなかったので、かなりショックを受けながら他の皆さんのゲームをプレイして癒やされてました。
いやーみなさん本当に凄い…。

2週目 月曜〜金曜

仕事が忙しく、基本終電帰りとなり殆ど着手出来てません…。

2週目 土曜〜日曜

この日にやっと原因がわかりました。
過去にiOSで言うNotification, Androidで言うEventBusライクな実装についての記事を書いたのですが、

www.project-unknown.jp

今回もこの設計を使っており、Scene切り替えのタイミングで通知の解除をし忘れていて、2週目以降は古い参照を保持し続けてしまった為に、古いGameObjectに通知されnullとなっていました。
まさかSubscribeして、Unsubscribeし忘れると言う初歩的なミス…。

この原因に気づいたのは本当にたまたまで、思考整理の為にリファクタしている最中に気づきました。

ここからは、残っていたUIを整えたり、WebGL用に解像度調整を行ったりして、やっとリリースすることが出来ました。

今回の反省点

過去の挑戦でも色々学ぶ事が多かったのですが、
今回は色々と反省すべき点が多い点で、物凄く自分の糧となったと思います。

後学へつなげる為に、反省点とその分析、next tryについて記そうと思います。(主に自分向け)

とにかく、今回は1つのバグを解決するのに凄い時間がかかったが、次回以降も何かに詰まってしまう事は大いに起こり得ると思ってます。
そこにどれだけ時間を掛けることが出来るかが大事で、他の難易度が低い所を以下に効率よく開発するかがポイントになりそうです。
(詰まる内容は読みにくいから、解決する時間を確保する方向で考える)

エターナル現象

今回は、企画の段階でエターナル化していました。
平日開発する時間が無いサラリーマンに、この規模を1週間で作るのは結構しんどいです。
システム開発に必要な不足な事態に対応できる程度のBufferの概念は持ち続けないといけないので、そうなると「捨てる判断」と「捨てる勇気」を成熟させる必要がありそうです。
ただ、逆に良かったのは作っている最中にあれもこれもはやらないように注意していたので、開発中のエターナル化が起きなかったのは良かったと思ってます。
と言うか、作ってる最中にもエターナル化してたらもっと時間がかかっていた事でしょう…。

どうすれば改善できるだろうか?

上記でも書きましたが、企画を作ったら、

  • 何を捨てるか?
  • 作るゲームのコアバリューは何か?

を考え、いちばん大切な所に時間を掛けて作るようにする。
それ以外は捨てる勢いで考えれるようにする。ここが私がかなり弱い所。

ただ、最低限の所(トップやらリザルトやら)は捨てにくい。
こういう所は、他でも使えるようなPrefabやPackage化して使いまわせるようにするべき。

資産を使いこなせていない

ゲームジャムが始まってから必要なアセットを見つけ出して勉強しだすのは効率が悪い。
企画を元に新規のアセットを導入する必要があるのならわかるけど、今まで購入したものについても、これまで一切触っていなくて、必要になって勉強し始めるのでは、ゲームジャムでは間に合わない

どうすれば改善できるだろうか?

  • やはり日々利用するアセットは勉強しておく必要がある。
  • Unityの勉強の意味で1から開発するでも良いが、私の目的はゲームを作って世に出す事。
  • その上で、車輪の再発明となることは可能な限り避けたい。
  • また、これをやる上で、平日取れて1時間くらいしか開発時間の確保が出来ないがここはどうするか。
    • 時間を分割するのが一番手っ取り早いが、そうなると30分がアプリやゲーム開発、もう30分が勉強となると、どちらもエンジンすらかからないと思う。
    • 日ごとに勉強の日、開発の日と分けるのがベスト。
      • 例えば、平日はゲームアプリ開発
      • 休日は半分が開発、もう半分が勉強
  • アセットのドキュメントを読むだけでは駄目。
    • 使っても忘れるのに、読むだけだと頭から速攻抜ける。
      • 実際にアセットを使って開発すべき。
      • 使った内容を、更にブログ等でアウトプットする事で、記憶の定着化を図る。

過去に開発したものを再開発している

アセットと同じ問題だが、過去に作ったものを新しいゲームでも再開発していた。
思い出して作る分、経験値稼ぎには良いが、こんなことをするくらいなら、やった事が無いことに力を注いだほうがスキルアップになりそう。

どうすれば改善できるだろうか?

  • 他でも使えそうなものはprefab化や、package化する。
    • 実はやっていたけど、管理の自分ルールが凄いことになっていて、いくつもプロジェクトが分岐し、何を使って良いのか、また管理コストが凄い事になっていた。
      • まずは、1つのプロジェクトに全てを纏める。

Unityを久々に触った

他のツール系アプリを開発しており、Unityを2,3ヶ月ぶりに触ったので思い出しに時間が掛かった。

どうすうれば改善できるだろうか?

  • 他のアプリを作っている時はUnityを触らないのは仕方ない
    • 上述した勉強の時に触ることで、忘れを防ぐ
    • アセットや共通処理の勉強やってりゃ忘れるのは防げるはず

利用Asset

主にSpriteの爆破解体に使っています。
こちらは主に2D用ですが、以下の用に3D用もあります。

ステートメントAssetです。PlayMakerが有名所ですが、Arborは自分での拡張が本当にやりやすいので、こちらを愛用させてもらっています。

保存機能を簡単に実装、Debugする為のAssetです。