見出し画像

【Unity】【unity1week】2DARPG講座を応用した「冬眠に備えるリス」でunityroomのゲームジャム「お題:ためる」に参加してみた!【備忘録】

2022年09月05日(月) 00:00 〜 2022年09月11日(日) 20:00の期間でunityroomでゲームジャムが開催されていたので、参加しました!お題は「ためる」で、自分は「冬眠に備えるリス」というゲームを投稿しました!

unityroomのゲームジャムに参加するのは2回目です。
↓1回目の記事

今回はUdemyの以下の講座で作ったゲームを改造して、ゲームを作りました。この講座では見下ろし方のARPGの作り方が学べます。昔のゼルダの伝説や聖剣伝説みたいなゲームですね。

ちなみに自分は「ゼルダの伝説」「ゼルダの伝説 神々のトライフォース」「ゼルダの伝説 夢を見る島」あたりが凄く好きなので、いつかちゃんとした2DアクションRPGを作りたいです。

では、以下に今回のゲーム作成の学んだこと、忘れたくないことを羅列していきます。

1.同じ型の変数であれば、カンマ区切りで連続で宣言できる

    private float moveSpeed, waitTime, walkTime;

シンプル。でも、これあんまり教えてくれる人いない気がします。

2.斜め移動と上下左右移動の速さを揃える

public Rigidbody2D rb;
///中略///
//.normalizedでベクトルの大きさを正規化し、斜め移動のスピードを上下左右の移動スピードに合わせる
   rb.velocity = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")) .normalized * moveSpeed;

以下の記事も参照していただきたいのですが、X軸の入力とY軸の入力を受け取ってオブジェクトを移動させる場合、斜めの移動が速くなってしまうようです。それを防ぐために「正規化」をして、斜めの移動スピードを調整します。

3.2Dタイルマップコライダー+2D複合コライダー+コンポジットで使用で引っかかりがなくなる

2Dタイルマップコライダーはタイルマップにコライダーをつけてくれる素晴らしいコンポーネントですが、2D複合コライダーと併用すると、タイルマップコライダーが結合して、コライダーの継ぎ目がなくなります。

4.変数の基本事項

今更ですが、以下おさらいです。

private int a; //このスクリプトでしか使えない。インスペクタにも表示されない。
public int b; //他のスクリプトからもアクセスできる。インスペクタにも表示される。

[SerializeField]
private int c;//このスクリプトでしか使えないが、インスペクタには表示される。

[System.NonSerialized]
public int d; //他のスクリプトからもアクセスできるが、インスペクタには表示されない。


5.ブレンドツリーで移動時のアニメーションを切り替える

X軸方向とY軸方向の力のかかり具合から、アニメーションを切り替えることができます。講座では上下左右でしたが、上の記事では斜めも判定しています。

講座内ではプレイヤーにブレンドツリーは使っていましたが、敵には使っていませんでしたので、自作してみました。

    private void MoveAnimation() {
        if (Mathf.Abs(moveDir.x) >= Mathf.Abs(moveDir.y)) {//Mathf.Abs(x)でxの絶対値を算出。Vector2のxとyの絶対値が大きいほう、
                                                           //つまりxが大きいなら横方向のアニメを再生する。
            if (moveDir.x >= 0) {
                enemyAnim.SetFloat("X", 1f);//アニメーターのパラメータXを1に
                enemyAnim.SetFloat("Y", 0);
                left.SetActive(false);
                right.SetActive(true);
                front.SetActive(false);
                back.SetActive(false);
            } else {
                enemyAnim.SetFloat("X", -1f);//アニメーターのパラメータXを‐1に
                enemyAnim.SetFloat("Y", 0);
                left.SetActive(true);
                right.SetActive(false);
                front.SetActive(false);
                back.SetActive(false);
            }
        } else {
            if (moveDir.y >= 0) {
                enemyAnim.SetFloat("X", 0);
                enemyAnim.SetFloat("Y", 1);//アニメーターのパラメータYを1に
                left.SetActive(false);
                right.SetActive(false);
                front.SetActive(false);
                back.SetActive(true);
            } else {
                enemyAnim.SetFloat("X", 0);
                enemyAnim.SetFloat("Y", -1);//アニメーターのパラメータYを-1に
                left.SetActive(false);
                right.SetActive(false);
                front.SetActive(true);
                back.SetActive(false);
            }
        }
    }

moveDirはVector2であり、xとyの2つの数値を持っています。
そのXとYの「絶対値」を比較し、大きいほうに対応するアニメーションを再生するというものです。
つまりX方向(横方向)の力が大きいときは、横方向に移動するアニメーションを再生し、Y方向(縦方向)の力が大きい時には、縦方向に移動するアニメーションを再生するということです。

6.敵の正面に入らない限り、追いかけられない仕組みを作れ

5の続きです。5のコードでは、SetActiveでtrue、falseを切り替えているleft、right、front、backは空のオブジェクトにコライダーをつけたものです。
敵キャラが向く方向の前方のオブジェクトがtrueになり、そのコライダーにプレイヤーが触れると、敵が追いかけてくるという仕組みです。
講座の方法では敵とプレイヤーの距離で判定していたので、ステルス要素が減ってしまいます。自分はあくまで敵の正面に入らない限り見つからないというメタルギアライクなシステムにしたかったのです。

7.ソートレイヤーについて

オブジェクトやUIの描画順はややこしい!

8.残り日数カウントダウンを実装せよ

以下のコードで「冬まであと〇〇日」という表示を実装できたのだが、毎回同じようなことをやっていても忘れてしまいますね。

    void Update() {
        limitDay -= Time.deltaTime;
        int i = (int)limitDay;
        DaysText.text = "冬まであと"+ i.ToString("d2") +"日";

        if (limitDay <= 0) {
            // 0秒になったときの処理
        }
    }

9.オンラインランキングとUpdate関数

上記の記事のやり方で今までもオンラインランキングを実装してきましたが、今回は上手くいかなくて焦ってしまいました。
コードは以下のとおりです。

    void Update() {
        if (limitDay <= 0 && !resultOn) {
            // 0秒になったときの処理
            DaysText.text = "冬到来!!";
            if (totalDonguri > 35) {
                resultSprites[0].SetActive(true);
                resultText.text = "今年の冬眠は豪勢だ!";
            }else if (totalDonguri>25) {
                resultSprites[1].SetActive(true);
                resultText.text = "余裕をもって冬が越せそう!";
            } else if (totalDonguri>15) {
                resultSprites[2].SetActive(true);
                resultText.text = "ちょっとひもじい……。";
            } else {
                resultSprites[3].SetActive(true);
                resultText.text = "こんな備蓄で大丈夫か?";
            }
            resultDonguri.text = "集めたドングリ:" + totalDonguri+"個";
            resultPanel.SetActive(true);
            risu.SetActive(false);
            // Type == Number の場合
            naichilab.RankingLoader.Instance.SendScoreAndShowRanking(totalDonguri);
            resultOn = true;
            return;
        }

上手くいかなかったときのコードにはresultOn関数がなく、limitDaysが0以下のときは毎フレーム、上記の処理がかかっていました。つまり毎フレームもオンラインランキングを呼び出していて、おかしくなっていたのです。
かといってlimitDays==0のときに「もうオンラインランキング」は呼ばなくていいよ、っていう処理を行うと、limitDaysがぴったり0のフレームをスルーしまうためか、上手くいきませんでした。

なので、limitDaysが0以下のときに呼び出し、resultOnというbool値を入れることで、一度は呼ばれるけど、二度は呼ばれないという処理が可能になりました。

この記事が気に入ったらサポートをしてみませんか?