としるみSoftの制作ブログ

主に作っている作品の紹介や今やっている活動の紹介を書いています。おすすめポイントですらなくなっちゃった。

1週間チャレンジ(ゲーム制作)

どもです、としです。

 

せっかくのゴールデンウィークなので、Unityで簡単なゲームを1週間ぐらいで作れないかチャレンジしたくなったのでやってみました。

以前にやった通りに1日単位でできた範囲を下書きで記録していきます。

 

 

1:1日目

あれこれ迷った結果、作るゲームはスライドパズルにしました。

まずは久しぶりに起動したのでアップデートがメインでした。

あとは簡単な絵を作りました。

雑です

始めから16個は多いかもしれませんが、思い切って始めから16個にしました。

あとはこれをどう動かすかを考えていかないといけません。

1日目はとにかく準備をして終わりました。

 

2:2日目

とにかく配置をしないと動かすこともできないので、とにかく配置することを優先して作業を進めました。

なんとか1つのPrefabを作って複製して配置はできました。

見た感じはいいようだけど……

配置する時にintとfloatの違いで何度か悩まされてしまいました。

余りはintで出てきたのですが、割り算はfloatになってしまいその辺で少し詰まりました。

なんやかんやで配置は何とかできたのですが、画像周りで結局詰まってしまいこの日は諦めました。

実際はそれぞれ画像を異なるようにするために先にSprite型の配列を作って、画像の準備はしました。

Sprite型の配列が作れた

ところが、この画像をうまく使うコードを書くことができなかったので、詰まってしまった感じです。

動作を行う以前に配置で詰まるとは情けない話です。

 

しばらく考えてやり方を変えてみたら何とかできました。

できたけど?

SpriteRendererを読み込むのを忘れていたのと、格納した画像の使い方を変えたので何とかできた感じです。

画像はゲーム全体のスクリプトに格納していましたが、

始めはパネル用のスクリプトで変更しようとしていて失敗していたので、

ゲーム全体のスクリプトで画像変更を行ったら行けました。

とりあえずここでストップにしますが、あとあと修正が必要になりそうです。

 

3:3日目

前にできたスクリプトを改良して最初の配置で数が1つを除いてランダムに配置されるようにします。

乱数を作る時に重複しないように作らないといけなかったので、

リンク先を参考にやりました。

tech.pjin.jp

リンク先ではList型の動的な配列を作り、それに数字を順番ずつ代入しています。

その後Unityの機能のRandom.Rangeを使ってどの番号の配列を読み込むか決めて、

配列の中身を代入してから使った配列を消去して配列を縮めている感じです。

それを使ってパネルの配列の長さ-1分の重複無しの乱数を作り、

最後の部分を手動で代入するようにしました。

(乱数は0から配列の長さ-2、最後に代入するのは配列の長さ-1。配列の長さが16ならlengthは16だけど、使う配列は0から15の16個。)

その後、配置の数字をループ用の変数iではなく作った乱数にして、

ゴール(i)の数字は現在乱数で作った数字の場所にいるようにできました。

できている?

次の準備のために最後のパネルだけ色を変更したいので、色の変更をしました。

SpriteRendererでやるのはなんとなくはわかりますけど、やり方がわからない(やったかもしれないけど忘れた)ので調べて変更しました。

meimaru.hatenablog.com

Color変更の時にRGB値を設定せずにColor.blackにしたら真っ黒になりました。

RGB値のそれぞれの最大値になる色はたぶんあるんだと思います。

真っ黒になった!

とりあえずまだゆっくり色を変える動作は付けないので今はこのまま次の段階に進んでいきます。

 

4:4日目

動かすのはともかく、当たり判定だけでもできたらいいなーという感じで進めました。

当初の予定はRayCastを使って、真っ黒の部分の上下左右にあるパネルを判定させて入れ替えるという感じです。

一番ややこしいのは操作がリバースになっていることで、上を入力したら下のやつを探すぐらいです。

とりあえずマウスは今は除外してキーボード入力で真っ黒のところから、入力した方向に光線を伸ばして値(ゴールの値)を手に入れるようにします。

RayCastで当たるようにしたのですが、自分自身を返してしまうバグが発生しました。

複数回は後で何とかする

Prefabで生成した同じオブジェクトなのでレイヤーによる回避は今のところ想定していませんので、回避方法を考えなければいけません。

むしろRayCastではダメなのかもしれません。

 

5:5日目

RayCastでダメだったので直接黒パネルを操作するようにし、ぶつけることで入れ替えを実行していきます。

まずは黒パネルを動かす段階からです。

同じPrefabを複製しているので、特定の番号のパネルだけを操作できるようにします。

その時に斜めに動かないようにしないといけません。

とりあえず動かした

今回は最後の番号のパネルを動かす動作にしているので、最後のパネルの番号と動かすパネルの番号(配列の最大値-1)で条件判定してtrueの時に操作できるようにしています。

Colliderのサイズが画像ピッタリだったので、起動した瞬間に当たるのでサイズを少し削りました。

入れ替えるコードを書く前に先に行かないようにするための壁を作っておきます。

どっちにしてもRigidbodyがKinematicでTriggerがオンになっているから、

オブジェクトがすり抜けてしまうのですり抜け防止は何とかする感じです。

最終的にRigidBodyはKinematicでTriggerはオフにしました。

壁用のオブジェクトを配置してColliderを配置して位置を調整したら、衝突判定で出なくなりました。

パネルのPrefabのRigidbody2D

ただ、UseFullKinematic~をオフにするとすり抜けるので、これはオンにしています。

その後OnCollisionEnter2Dを使って入れ替えをやってみたのですが、なかなかうまくいかなく何時間か悩みました。

しばらく悩んでバグの原因が1文が抜けていただけでした。

この段階でのOnCollisionEnter2Dはこんな感じです。

(Prefabのパネルに入っているPanelManagerのコード)


    void OnCollisionEnter2D(Collision2D collision)
{
    transform.position = mpos;
    if(PanelMaster == PanelGoal)
    {
        if(collision.gameObject.tag == "Wall")
        {
            Debug.Log("kabeに当たったで");
        }
        else
        {
            PanelManager pm = collision.gameObject.GetComponent();
            // 当たった相手の情報
            Vector2 tpos = collision.gameObject.transform.position;
            int tnum = pm.CallNumber();
            // 当たった相手に自分の情報を送る
            pm.ChangePositon(transform.position);
            pm.ChangeNumber(PanelNumber);
            // 自分の情報を手に入れた情報に変える
            ChangePositon(tpos);
            ChangeNumber(tnum);

            Debug.Log(collision + "に当たったで");
        }
    }
}    
    

始めのtransform.positionは入れ替えた時に位置がブレないようにするために置いたもので、初めの値は初期位置のVector2が入っています。

ちなみに悩んだ原因がこれでした。

次のif文はPrefabで作ったオブジェクトなので、特定の番号のみ反応するために入れたものです。

これで真っ黒のオブジェクトだけ反応します。

タグ判定は今のところは使っていませんが、念のために置いています。

当たったパネルのPanelManagerを読みだしてpublicに設定したメソッドを読みだして値を変更できるようにしています。

ChangePositionは引数のVector2の値に自身の位置を変更するメソッドです。

ここで初期位置用の変数mposの値を変えなかったのでバグって悩みました。

ChangeNumberは位置番号の入れ替えを行っています。

この番号と初期設定したゴール番号を一致させるのを目的にする感じです。

pmの方は衝突された方、無しの方は衝突した方(真っ黒)になっています。

うごいた!

動かすスピードは今は置いといて、何とか目的通りに近づいています。

あとはゴール判定を作って、スタートとゴールエフェクトを簡単に作ればとりあえずの段階はできそうです。

 

6:6日目

入れ替えができたのでいよいよゴールを作らないといけません。

ゲーム管理用のスクリプトにゴール判定を付けました。

まずは判定用にbool型変数を作らないといけないのですが、

エラーに悩まされてできた結果を書きますと、

パネル管理用のスクリプトにPublic型のBoolを作成し、

管理番号とゴール番号が一致した時にTrueを返すようにしました。

そのBoolをゲーム管理用のスクリプトで読み出し、

ゴールしたパネルをカウントした変数がパネルの総数と一緒になれば、ゴールと表示してそうでなければゴールカウント変数を0にするという感じです。

バックログで確認できた。

ここまでできたら後はスタートとゴールのUI周りと操作受付のオンオフを書くことができれば、

ほとんどとりあえず完成と言えるレベルにできそうです。

すでにゲーム制御用のbool型変数は仕込んでいるのであとはそれが使えるようにする感じです。

 

この前やったUnityLearnの項目を見直してUIDocumentを使ってUIを作成しました。

位置はゲームを起動して調整

その時の項目を参考にUIを設定していきました。

コード的には新しくUI用のスクリプトを作成しました。

UI用のスクリプトでゲーム管理用のスクリプトを読み込ませるようにし、

ゲーム管理用のスクリプトのゲーム管理bool型変数を読み込ませるようにして

UIの表示を制御しました。

表示時間の方はゲーム管理用スクリプトの方でやったので、

UI用の方はほとんど表示の制御だけです。

スタート

クリア

やっとほぼできた感じになります。

あとは細かなバグ取りを行えば、何とかチャレンジがうまくいきそうです。

 

7:まとめ

とりあえずWeblog更新日になったのでチャレンジは終了です。

バグはまだ残っているものの一通り遊べるものが仕上がったので、

チャレンジとしては成功と言ってもいいかもしれません。

調べながらも意外と1週間でここまでできたので、

結構なんだかんだ基礎的な知識は身に付けられているのかもしれません。

あと残りのバグを解消してから、次に進んでいく感じです。

そろそろやらねばと言い続けているMidi検定の本を読まないといけないので、

次に1週間でチャレンジは音楽制作にしてもいいかもしれません。

どっちにしても進まないことには何も始まらないです。

今回のこのチャレンジはやりたいゲーム制作のちょっとした自信につながったので、

自己満足としてはいい感じです。

 

ということで今日はこれにて!

では!

 

(追記)

最後のバグは変数を代入する位置が間違っていて、

減らして0以下にして次に進むコードなのにUpdeteの度に初期値に戻っていたので、

先の動作に進まなかったです。

直って仕様通りになりました。