Unityで最低限知っておきたいプログラムの知識(3/3)関数の使い方

ころもちゃん

プログラミングの処理の読み解き方についてもっと教えて

本記事の内容

・プログラム基礎知識(変数・関数)について理解しよう
・関数の、引数・返り値を理解しよう

目次

前回のまとめ

スクリプト全体の構成と、スクリプトで定義した変数を使って関数で処理を行うというのが基本です、という解説をしました。詳しくはこちらの記事を参照してください。

関数について理解してみる

実際のサンプルのコードで見てみる

今回は、プログラムの一番メインの部分、関数というものについて見ていきましょう。

まず、プログラムを書くファイルのことを「スクリプト」と呼びます。
Unityでスクリプトを作成してみましょう。プロジェクトウィンドウで、右クリック→[C#スクリプト作成]をして、ファイル名には「PlayerMovement」と付けてみましょう。

ここに、プレイヤーからのキーボード(矢印キー)の入力を受け付けて、移動するプログラム例を作成しました。

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    public float moveSpeed = 5f; // 移動速度のパラメータ
    private Rigidbody rb;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
        // 十字キーの入力を取得
        float moveHorizontal = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");

        // 移動ベクトルを計算
        Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);

        // Rigidbodyを使ってプレイヤーを移動させる
        rb.MovePosition(transform.position + movement * moveSpeed * Time.deltaTime);
    }
}

※RigidBodyについては、別途解説予定です。

このコードの中の、冒頭にある
「public float moveSpeed = 5f; // 移動速度のパラメータ」、これが、変数です。

そして、その下にある以下の内容が関数(メソッド)です

void Start()
{
    rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
    // 十字キーの入力を取得
    float moveHorizontal = Input.GetAxis("Horizontal");
    float moveVertical = Input.GetAxis("Vertical");

    // 移動ベクトルを計算
    Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);

    // Rigidbodyを使ってプレイヤーを移動させる
    rb.MovePosition(transform.position + movement * moveSpeed * Time.deltaTime);
}

また、関数(メソッド)の中に、最初に定義した変数、moveSpeedという文字がありますね。
これにより、指定したmoveSpeedの速度(今回は5.0)でプレイヤーが移動することができます。

スクリプトにコードを貼り付けてみよう

先程のコードを、作成したスクリプトファイルに貼り付けてみます。

そして、作成したスクリプトを、動かしたいキャラクターにアタッチしてみましょう。
私は、今回こちらの無料アセットを使用して、キャラクター画像をUnityに取り込みました。

あわせて読みたい
Knight Sprite Sheet (Free) | 2D Characters | Unity Asset Store Elevate your workflow with the Knight Sprite Sheet (Free) asset from Kin Ng. Find this & more Characters on the Unity Asset Store.

動かしたいキャラクターにスクリプトをアタッチするには、スクリプトのファイルをドラッグアンドドロップするだけです。
また、RigidBodyというコンポーネントも追加して、「重力を使用する」をOFFにしてください。下のGIF画像と同じことをやってもらえれば大丈夫です!
もし動いていない場合は画像をクリックしてみてください


また、変数の定義に「public」という文字がついていましたね。これにより、プログラム内のコードを書き換えずとも、エディタ画面で値を調整することができます。属にいうパラメータ調整ですね。

この状態で実行ボタン(▷ボタン)を押してみましょう。
すると、キーボード入力でキャラクターが動くようになったはずです。

そして先程のPlayerMovementのMoveSpeedの値を変更すると、キャラクターの移動速度が変わることを確認してみましょう。

関数のバリエーション、引数・返り値の使い方を理解しよう

関数の基本

このように関数内にやりたいことを記載して、処理を動かしていくというのがプログラムの基本です。
そして、重要な点が、関数は入れ子構造(カプセル化)にして作成する、ということです。詳しくはこちらの記事を参照してください。


大きなメインの関数があり、その中に小分けにした関数を持っている、というイメージです。
たとえば、ボタンを押したら、Aというオブジェクトを消して、Bというオブジェクトを表示するということをするなら・・・

  • Aというオブジェクトを非表示にする関数・・・(1)
  • Bというオブジェクトを表示する関数・・・(2)
  • (1)と(2)を実行する関数

の3つを作成する、といった具合です。
このようにすることで、別の処理でCという画面を消したいとなった場合に、(1)と同じコードを使い回すことが出来るようになり、効率的に進めることが出来るのです。

引数(値を受け取る)を持つ関数

先程挙げた例で、プログラミングの基本はコードを使い回す、という話をしました。
では、「Aというオブジェクトを消す関数」と「Cというオブジェクトを消す関数」を使い回すにはどうしたらいいのでしょうか?

そのためには、「どのオブジェクトなのか」という指定と、「指定した対象を消す処理」が必要です。
この、「どのオブジェクトなのか」というのが引数になります。具体例で見てみましょう。

例えば先程の「Aというオブジェクトを消す関数」を実装する場合、このような関数になります。

public void DeactivateGameObject(GameObject obj)
{
    if(obj != null)
    {
        obj.SetActive(false);
    }
}

DeactivateGameObjectというのが、この関数名です。そして、(GameObject obj)が、引数です。引数には型を指定する必要があります。この関数の型は、GameObjectという型のようです。

型についてはこちらで解説しているので良かった見てください。

そして、受け取った引数に対して、SetActive(false)という処理を行うことで、対象のオブジェクトを非表示にすることが出来ます。こうすることで、Aというオブジェクトでも、Bというオブジェクトでも、Cというオブジェクトでもこの関数を使いわ回すことが出来るわけです。

同様に関数(2)も作ってみましょう。先程のSetActiveのカッコ内がtrueになっただけなので変化はほとんどありませんね。

public void ActivateGameObject(GameObject obj)
{
    if(obj != null)
    {
        obj.SetActive(true);
    }
}


では最後に、関数(3)「Aというオブジェクトを消す関数 + Bというオブジェクトを表示する関数」を作ってみましょう。その場合、このようなコードになります。

    public GameObject aObject;
    public GameObject bObject;

    // aObjectをアクティブにし、bObjectを非アクティブにするメソッド
    public void MethodC()
    {
        ActivateGameObject(aObject);
        DeactivateGameObject(bObject);
    }

aObjectbObjectは、変数です。これらの値は、インスペクタ画面で設定することが出来ます。
そして、ActivateGameObject(aObject)としたので、ActivateGameObjectが、aObjectを引数にとって実行されます。
同様に、DeactivateGameObject(bObject)としたので、DeactivateGameObjectが、bObjectを引数にとって実行されます。
例えば、この処理を実行するタイミングで、アクティブにしたいオブジェクトを別のオブジェクトにしたいのでであれば、以下のように、aObjectの対象を変えてあげれば、できるだけコードをいじらずに、柔軟な変更が出来るわけです。

    public void MethodC()
    {
        aObject = xxxObject;
        ActivateGameObject(aObject);
        DeactivateGameObject(bObject);
    }

・引数を取る関数を呼び出すときに引数を入れないコードはエラーになります。
例えば、ActivateGameObject()とすると、エラーになってしまいます。

このように、基本的に一つのスクリプトに対して、小分けにした関数があり、それらを組み合わせた大きな関数がある。そして、その関数の実行条件として、”引数”というものを指定出来るということを覚えておきましょう!

返り値(計算結果を出力する)を持つ関数

最後に、返り値を持つ関数について紹介します。これで最後です!
返り値と聞くとわかりづらいのですが、要は計算結果を算出して教えてくれる関数、みたいなものです。

具体的に見てみましょう。これまで出てきたサンプルの関数は、いずれもこのようになっていました。
public void [関数名](引数){}

このvoidというのは、引数を取らない、という意味になります。あまり馴染みのない英単語ですね。
voidという部分を、変数の型にしてあげることで、返り値を持った関数を作ることが出来ます。

サンプルのコードはこちらです。

    // ダメージ計算を行うメソッド
    public int CalculateDamage(int attackPower, int defense, int baseDamage)
    {
        int damage = baseDamage + attackPower - defense;

        return damage;
    }

詳しく見てみましょう。まず、public intとなっているので、この関数はint(整数型)の計算結果を返してくれます。そして、先程出てきた引数がこの関数にもありますね。(int attackPower, int defense, int baseDamage)の箇所です。
そして、return damageと最後にありますが、このreturnとついている変数に計算結果が入ります。
逆にreturnがついていないとエラーになっていまいます。

つまり、この関数は引数として取得した、attackPower、defense、baseDamageの数値を元に敵与えるダメージを計算してくれる関数ということですね。

この関数を呼び出す関数についても見てみましょう。たとえば、敵にダメージを与えるには、このような関数構造を作る必要があるわけです。

    public int enemyHp = 100; // 敵の初期HP

    // ダメージ計算を行うメソッド
    public int CalculateDamage(int attackPower, int defense, int baseDamage)
    {
        int damage = baseDamage + attackPower - defense;

        return damage;
    }    


    // 敵にダメージを与えるメソッド
    public void DealDamageToEnemy(int attackPower, int enemyDefense, int baseDamage)
    {
        int damage = CalculateDamage(attackPower, enemyDefense, baseDamage);
        TakeDamage(damage);
    }

    // 敵がダメージを受けた時にHPを減らすメソッド
    public void TakeDamage(int damage)
    {
        enemyHp -= damage; // 受けたダメージをHPから引く
    }

CalculateDamageというのが先ほど見た、返り値(≒計算結果)を教えてくれる関数でした。
なので、int damage = CalculateDamage(attackPower, enemyDefense, baseDamage)という処理によって、damageという変数に、ダメージ量を計算した結果(基礎攻撃力+武器攻撃力ー敵の防御力)をセットしています。
そして、そのdamageという変数の値を、TakeDamage(damage)という処理の引数にセットしてダメージ量分、敵のHPを減らすという処理を行っています。

返り値(計算結果を出力する)を持つ関数についてでした。

まとめ

最終回とあって、少し難しい内容もあったかと思います。ですが、これだけ理解してみましょう。

  • 関数は入れ子構造になっていて、複数の小分けにした関数を呼び出して処理を作る
  • 関数は、引数を取る、返り値をつける のオプションがある
  • 引数はその関数の実行対象を呼び出すときに指定出来る
  • 返り値をつけると、計算結果を返してくれるようになる

分からないことがあればChatGPTに聞くといいでしょう。このブログよりもピンポイントに回答してくれるでしょう。

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

ゲーム制作の敷居を下げ、もっと多くの人にゲーム作りを楽しんでもらうために、ゲームをカンタンに作る方法を”網羅的に”解説しています。
よかったらブックマークお願いします。
Twitter(X)もよければフォローお願いします。

コメント

コメントする

目次