Developer

【初心者Unity】懐かしのゲームを作ってみよう!②
2021.10.01
Lv1

【初心者Unity】懐かしのゲームを作ってみよう!②


はじめに

今回は前回に引き続き、↓のゲームを作っていきます。

今回は前回作成した「Ball」をプログラミングで動かしましょう!


第2段階:ボールを作成しよう!(2)

Ballをプログラミングで動かす方法ですが、Unityでは主にC#を使って動かします。C#の画面への行き方は↓の写真の通りです。まずHierarchyタブのBallをクリックします。するとInspectorタブにBallの詳細が表示されるので、一番下のAdd Componentをクリックします。するとまた一番下にNew Scriptが現れるのでそれをクリックし、スクリプト名を決めます。今回は「BallScript」と名付けました。最後に作成されたスクリプトをダブルクリックすればスクリプトがVisual Studioで開かれます。

Visual Studioを未だインストールしていない方はこちらの記事を参照▶【初心者Unity】Visual Studioのインストール方法

それではいよいよプログラムを書いていきましょう!と言いたいところですが、まずはどのようなプログラムを書いていくか大まかな方針を考えなければいけません。いわゆる「(詳細)設計」と呼ばれるフェーズですね。
まず、ボールにどの様な動きをしてほしいか考えたときに、やはり一般的に斜め45度ですっ飛んでってほしいですよね!ということでまずは斜め45度方向に進ませます。
次に、反射です。上下左右の画面の際に来たら跳ね返ってほしいですよね?まさかそのまま画面アウトしても永遠に45度で進み続けてほしいなんて方はいらっしゃらないですよね?(笑)
ということで今回の記事では下記の2つを実現させます。
①斜め45度に進ませる
②上下左右の画面際に来たら跳ね返らせる

これを早速プログラムに反映させると下記の様になります。
デフォルトで用意されているStart()メソッドとUpdate()メソッドの説明は割愛させていただきます。

StartメソッドとUpdateメソッドがよくわからない方はこちらの記事を参照▶【初心者Unity】UnityとC#におけるメソッド一覧
public class BallScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        //斜め45度に進ませる
        Move();

        //右端に着いた時の処理
        if (IsRightEdge())
        {
            //何かの処理
        }

        //左端に着いた時の処理
        if (IsLeftEdge())
        {
            //何かの処理
        }

        //上端に着いた時の処理
        if (IsUpperEdge())
        {
            //何かの処理
        }

        //下端に着いた時の処理
        if (IsLowerEdge())
        {
            //何かの処理
        }
    }
    
    //以下Updateメソッド内で動かすメソッド群
    
    void Move()
    {
        //処理
    }

    bool IsRightEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsLeftEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsUpperEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsLowerEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }
}

何とも雑に思われた方も多いのではないでしょうか?
重要なところはコメントアウトやメソッドでごまかしてるし何なんだと言いたくなりますよね?(笑)
ただ、最初はこんな感じで大雑把に書きましょう。そして、実際の処理はUpdate()メソッド外のメソッド群の中に書いていきましょう。
なぜこんな面倒くさいやり方をするのかというと、ひとえに可読性を上げるためです。
仮にあなたがこのゲームを作成した本人ではなく、保守するだけの人であったとしましょう。バージョンアップのためにこのゲームのコードを見直す際にまずはどこを見るか。。。
そうメインのUpdate()メソッドを見るんです!
その際に、Update()メソッド内がごちゃごちゃしていると、保守の際に何が何だか分からなくなってしまいます。
対して今回のスクリプトにおけるUpdate()メソッドはいかがでしょうか?メチャクチャ見やすくないですか??
まず一番上にMove()とあるので、ああ、基本は動くのね、と分かります。
そしてIs~Edge()というのが4つあるので、ああ、端っこに着くとここで処理を変えるのね、というのが伝わってきます。
これによって書いて終わりのスクリプトではなく、今後の保守がしやすいスクリプトを作成することができます。
また、作成する際にも「設計」と「開発」の工程を分けながら作成することができるので、慣れると開発もしやすくなります。
閑話休題。。。
上のスクリプトで方針は決まったので今度は詳しい処理を、主にUpdate()外のメソッド達に書き加えていきましょう。
まずは1つ目の「斜め45度に進ませる」ですが、こちらはお察しの通りMove()メソッド内に具体的な処理を書いていきます。
具体的な処理としては、Ballの座標をx軸方向とy軸方向に均等に増加させていくことによって、さながらy=xの一次関数の様な軌跡を描かせましょう。
イメージとしては、1フレーム毎にBallのx座標を1増加かつy座標を1増加させていく感じです。
何言ってるかよくわからない方は↓の写真とにらめっこしながら上の文を再度読んでみてください(笑)

実際のプログラムとしては以下のスクリプトになります。
先ほどのスクリプトに書き足した形になりますが、大した量は加えていません。
スクリプトの説明としてはまず、座標を操作することで移動させるため、座標に関するVector2型の変数「pos」を用意します。
次に、このposを初期化する必要があるため、Start()メソッド内で現在のBallの座標を代入します。
そしていよいよMove()メソッド内に処理を書いていきます。今回は上の設計で書いた様に「1フレーム毎にBallのx座標を1増加かつy座標を1増加」させていきます。したがって、posのxとyの値をそれぞれ1加えます。
最後にposの値をBallに反映させれば完成です。

public class BallScript : MonoBehaviour
{
    Vector2 pos;
    // Start is called before the first frame update
    void Start()
    {
        pos = transform.position;
    }

    // Update is called once per frame
    void Update()
    {
        //斜め45度に進ませる
        Move();

        //右端に着いた時の処理
        if (IsRightEdge())
        {
            //何かの処理
        }

        //左端に着いた時の処理
        if (IsLeftEdge())
        {
            //何かの処理
        }

        //上端に着いた時の処理
        if (IsUpperEdge())
        {
            //何かの処理
        }

        //下端に着いた時の処理
        if (IsLowerEdge())
        {
            //何かの処理
        }
    }

    void Move()
    {
        pos.x += 1;
        pos.y += 1;
        transform.position = pos;
    }

    bool IsRightEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsLeftEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsUpperEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsLowerEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }
}

いかがでしょうか?今、Ballを動かすためにUpdate()メソッド内は一切変更しなかったのが分かりますか?
これが、最初にざっと書いてしまうことの良さであり、保守のしやすさにつながってきます。(そして正にオブジェクト指向的なんですねぇ。。。しみじみ)
それではせっかくなので実行してみましょう!
実行の仕方は、↓の写真の通りです。

↓の様にスン!と一瞬にして消えてしまったのではないでしょうか?(笑)

毎フレーム毎にxとyをそれぞれ1進めるのはいささか速かったようですね。。。
私の方で速度調節したところ、それぞれ0.03ずつ位がちょうどよかったので皆さんもその前後の数字にしておくと良いのではないでしょうか?
念のため下記にスクリプト貼っておきます。

public class BallScript : MonoBehaviour
{
    Vector2 pos;
    // Start is called before the first frame update
    void Start()
    {
        pos = transform.position;
    }

    // Update is called once per frame
    void Update()
    {
        //斜め45度に進ませる
        Move();

        //右端に着いた時の処理
        if (IsRightEdge())
        {
            //何かの処理
        }

        //左端に着いた時の処理
        if (IsLeftEdge())
        {
            //何かの処理
        }

        //上端に着いた時の処理
        if (IsUpperEdge())
        {
            //何かの処理
        }

        //下端に着いた時の処理
        if (IsLowerEdge())
        {
            //何かの処理
        }
    }

    void Move()
    {
        pos.x += 0.03f;
        pos.y += 0.03f;
        transform.position = pos;
    }

    bool IsRightEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsLeftEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsUpperEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }

    bool IsLowerEdge()
    {
        //一時的に「false」にしてるだけ後で処理書く
        return false;
    }
}

因みに、0.03にすると↓の様な速さで動きます。


おわりに

いやーようやくBallが動きましたね。
Unity上で何かが動くというのは中々に感動的かと思います。
実は今回でBallの動きは一通り完成させる予定だったのですが、
当初の想定以上に書きすぎてしまったので今回はここまでにとどめておきます。。。
次回はいよいよBallを跳ね返らせる処理です!
これでBallの処理はひとまず完了します!
乞うご期待!

 


連載目次リンク

「初心者のための」Unityゲーム制作 目次

Unity実践編 - 目次リンク

実践Unityゲームプログラミング 連載目次