俺の霊魂を越えてゆけ。 をつくった話

発端

つくるUOZUプロジェクトというものがあります。
富山県魚津市という、どこにあるのかよくわからない田舎の町で、
ゲームで町おこしをするぞ!
……という、なんだかどこかで聞いたような。
そんなことを掲げているプロジェクトです。

しかしつくるUOZUが他とちょっと違うのは、
「ゲーム会社を誘致する」
のみを目的とするのではなく、
「ゲーム開発の人材がたくさんいる町にする」
「ゲーム開発の人材を育成するサイクルを作る」
「創業支援をきっちり行う」
などを同時に目指していることにあります。

とまあそんなことはどうでもよくて、ハッカソンが開かれたんです、ハッカソン
東京なればいざ知らず、ここ富山県でゲームハッカソンが開かれるというのは、
もはや黒船、文明開化の波が来た、高度経済成長期、
とにかく珍しいことです。
行くしかない! 乗るしかないんです! このビッグウェーブに!!

1日目

というわけで、やってきました「UOZUゲームハッカソン 夏の陣」。
ゲーム会社からの仮想案件というテーマを完全に無視しまして、
「自分を犠牲にして後続の道を切り開く」
をコンセプトになんかつくることにしました。

ジャンルを考える

コンセプトを普通に読むと、
パズル要素かアクション要素のどちらかは必要であるように思われました。
なら、パズルアクションでいいかな?
というわけで、2Dプラットフォーマーをベースにやっていくことにしました。
惜しくも今日は持ってきませんでしたが、
和尚本にあったから思い出しながらできるかも!
Unityの寺子屋 定番スマホゲーム開発入門

プレイヤーキャラクターをつくる

さて、そうと決まれば、最低でもプレイヤーの実装は必須です。
あとは流れでなんとかなるでしょう。
今回はRigidbody2Dに全部お任せすることにしました。
とりあえずCapsule Collider2Dをつけておきます。
チームメイトが素晴らしい絵をかいてくださいました。

f:id:gforest_shade:20190727195256p:plain
PC

入力

入力を受け付ける処理を書いていきます。といっても、左右移動とジャンプができれば十分でしょう。

private void Awake()
{
    Rigidbody2D rigidbody = GetComponent<Rigidbody2D>();

    // 左右入力で左右移動
    this.UpdateAsObservable()
        .Where(_ => canMove)
        .Select(_ => Input.GetAxis("Horizontal"))
        .Subscribe(input =>
        {
            transform.localPosition += Vector3.right * input * _MoveingSpeed;
            onPositionChanged.OnNext(transform.position);
        });

    // 右入力で右を向く
    this.UpdateAsObservable()
        .Where(_ => Input.GetAxis("Horizontal") > 0)
        .Subscribe(input =>
        {
            playerDirection.Value = 1;
            transform.localScale = new Vector3(1f, 1f, 1f);
        });

    // 左入力で左を向く
    this.UpdateAsObservable()
        .Where(_ => Input.GetAxis("Horizontal") < 0)
        .Subscribe(input =>
        {
            playerDirection.Value = -1;
            transform.localScale = new Vector3(-1f, 1f, 1f);
        });

    // ジャンプ入力でジャンプ
    // 上方向にAddForce()するだけ
    this.UpdateAsObservable()
        .Where(_ => Input.GetButtonDown("Jump"))
        .Subscribe(input =>
        {
            rigidbody.AddForce(Vector2.up * 4.7f, ForceMode2D.Impulse);
        });
}

接地判定をする

このままでは無限ジャンプできてしまうため、
接地しているかどうか判定しなければなりません。
すこし時間をかけていろいろ試したのですが、
無限に悩んでいるわけにはいかないので、
とりあえず接地判定用のColliderを最初からつけておくことにしました。

f:id:gforest_shade:20190727195256p:plain
下の四角がそれ

カレーを食べる

おいしかった!

ミスの仕組みをつくる

ミスの仕組み自体は、和尚本を思い出して参考にしました。
ステージ全体を覆うような大きいColliderをつくり、
そこから出たときに1ミスとして扱います。

f:id:gforest_shade:20190727204017p:plain
チームメイトからどんどんアートが上がってくる

ここで、
「ミスした地点に新しい足場を出現させ、 それをのりこえて進んでいく」
というアイデアが出たので、
コンセプトの解釈はそれでいくことにしました。
ステージにあらかじめ霊魂スポナーとスイッチを並べておいて、
「プレイヤーがミスしたとき、最後に触れていたスイッチに対応するスポナーから、霊魂(足場)を出現させる」
という実装にしました。

また、ミスすることが前提になるので、
ミスして霊魂を出したらプレイヤーを即リスポーンさせるようにしました。
いちいち操作や演出を挟むとゲームのテンポが悪くなると思ったためです。

温泉に入る

えがった。 www.kintarouonsen.co.jp

霊魂の種類を増やす

ギミックがひとつではさみしいので、
「生前にアイテムを取っておけば異なる種類の霊魂が出てくる」
を実装することにしました。

アイテムの絵、プレイヤーが形態変化した絵、新しい霊魂の絵などが
どんどん上がってくるので、どんどん実装しました。

f:id:gforest_shade:20190727214020p:plain
天使の羽
このあたりはPlayerControllerが神クラス化しないようにわりと気を付けていました。

ちゃんと寝る

えらいっ!

2日目

スクロール処理をつくる

この時点で一応コンセプトは実現していたので、
BGM・SE・背景・アニメーションなどのお化粧に手を付けつつ、
タイトル・ステージ選択などのアウトゲームもつくりつつ、
自分はスクロール処理をつくっていました。

カメラを気持ちよく移動させる処理を書くのが難しいことはわかっていましたので、
そこは思いっきり妥協したアルゴリズムでさくっと実装してしまいました。

あとはお化粧のほうをお手伝いしたりしつつ……

できた

できたー!

総括

たのしかったです。

できたやつ

unityroom.com