メソッドがわからない人へ ― まずコードを使わずに考えてみよう

広告

Unityでスクリプトを書いていると、こんなコードが出てきます。

void ShowMessage()
{
    Debug.Log("こんにちは");
}

これを見て、

  • voidって何?
  • ()は何?
  • どうしてわざわざメソッドにするの?
  • どこをメソッドにすればいいの?

と思った人もいるかもしれません。

この記事では、いったんコードから離れます。考えるのは次の3つだけです。

  • 分ける
  • まとめる
  • 名前を付ける

最後にUnityのスクリプトに戻って、実際にメソッドを作るところまで進めます。

メソッドがわからない人へ:コードで悩む学習者が、分ける・まとめる・名前を付けるの考え方で理解する様子
コードの形より先に、「分ける・まとめる・名前を付ける」を考える

1. まず「分ける」

「コンビニでお茶を買う」という行動を考えてみます。

これは一つの動作に見えますが、細かく分けると次のようになります。

店に入る
↓
飲み物売り場へ行く
↓
お茶を探す
↓
商品を取る
↓
レジへ行く
↓
代金を払う
↓
店を出る

「お茶を買う」という一つの行動の中に、いくつもの小さな行動が入っています。

分ける:コンビニでお茶を買う行動を、店に入る・お茶を探す・レジで払う・店を出るなどの小さな手順に分けた図
「お茶を買う」も、小さな手順に分けられる

プログラムも同じです。たとえば「成績を登録する」という処理は、

名前を入力する
点数を入力する
入力内容を確認する
保存する

のように分けられます。

大きな処理を小さな手順に分けること。これを分解といいます。

2. 次に「まとめる」

今度は逆です。次の行動を見てください。

歯ブラシを取る
歯磨き粉を付ける
歯を磨く
口をゆすぐ

これを一言で表すと「歯を磨く」になります。

まとめる:歯ブラシを取る・歯磨き粉を付ける・磨く・口をゆすぐの4つの手順を「歯を磨く」という1つの行動にまとめた図
いくつかの手順を、一つの行動としてまとめる

では、次はどうでしょう。

点数を見る
60点以上か確認する
60点以上なら合格、それ以外なら不合格と決める

これは「合否を判定する」とまとめられそうです。

プログラムでは、この

何行かの処理を、一つのまとまりとして見る

ことがとても大切です。

3. まとまりに「名前を付ける」

まとまりが見えたら、名前を付けます。

ここで一つ、大事なポイントがあります。

名前は「最後に何をするか」ではなく、「そのまとまりは何のためにあるか」で付けます。

次の2つを比べてみてください。

【まとまりA】
点数を見る
60点以上か確認する
合格か不合格か決める
【まとまりB】
点数を見る
60点以上か確認する
合格か不合格か決める
結果を画面に表示する

Aは「決める」ところで終わっています。目的は合否を決めることなので、名前は「合否を判定する」です。

Bは、決めたあとに表示までしています。目的は結果を見せることなので、名前は「結果を表示する」です。

手順がほとんど同じでも、何のためのまとまりかが変われば、名前も変わります。

この「処理に名前を付ける」という考え方が、そのままメソッドにつながります。

名前を付ける:何行かの処理をひとまとまりにしてShowMessageという名前を付け、Startから呼び出す流れ
まとまりに名前を付ければ、名前で呼び出せる

4. メソッドとは何か

ここでメソッドの話に戻ります。

メソッドとは、

いくつかの処理をひとまとめにして、名前を付けたもの

です。

さきほどの「結果を表示する」をC#で書くと、たとえば次のようになります。

void ShowResult()
{
    // 点数を見る
    // 合否を判定する
    // 結果を表示する
}

ShowResult が付けた名前です。そして、別の場所で

ShowResult();

と書くと、「結果を表示する」というまとまりが実行されます。これを「メソッドを呼び出す」といいます。

メソッドを作る(定義する)、呼び出す、実行されるの3ステップ
メソッドは「作る(定義する)→ 呼び出す → 実行される」の順に動く

実はもう使っている

Unityのスクリプトを作ると、最初から次のようなコードが入っています。

void Start()
{
}

void Update()
{
}

この Start や Update もメソッドです。

Start は「最初に一度やること」、Update は「基本的に毎フレームやること」を書くメソッドです。自分で作るメソッドとの違いは、自分で呼び出さなくても、Unityが決まったタイミングで呼び出してくれることだけです。

つまり、みなさんはすでにメソッドの中にコードを書いていたのです。

5. なぜメソッドにするのか

Aさん、Bさん、Cさんの3人の合否を表示する場面を考えます。

まとまりを意識せずに書くと、こうなります。

Aさんの点数を見る
Aさんの合否を判定する
Aさんの結果を表示する

Bさんの点数を見る
Bさんの合否を判定する
Bさんの結果を表示する

Cさんの点数を見る
Cさんの合否を判定する
Cさんの結果を表示する

よく見ると、3人とも

点数を見る
合否を判定する
結果を表示する

という手順はまったく同じです。違うのは「誰の点数か」だけです。

同じ手順を「結果を表示する」という一つのまとまりにしておけば、書くのは一回で済みます。合格ラインが60点から70点に変わっても、直すのは一か所だけです。

これがメソッドを使う大きな理由です。

同じDebug.Logを3回書く代わりに、ShowMessageメソッドにまとめて3回呼び出す比較
同じ処理を何度も書く代わりに、まとめたものを何度も呼び出す

では、「違うのは誰の点数かだけ」という部分は、どう扱えばよいのでしょうか。これが次の「引数」です。

6. 引数 ― メソッドに渡す情報

ここから先(6〜8章)は、「処理をまとめて名前を付ける」という意味がわかってから読めば十分です。

引数や戻り値がまだ難しく感じたら、いったん9章の練習1・3に進んでもかまいません。

この記事でいちばん伝えたいのは、5章までの内容です。

「結果を表示する」という手順は同じでも、使う点数は毎回違います。

85点で、結果を表示する
42点で、結果を表示する
60点で、結果を表示する

この「何点か」にあたる情報を、呼び出すときにメソッドへ渡す仕組みが引数です。

C#では、次のように書きます。

void ShowResult(int score)
{
    if (score >= 60)
    {
        Debug.Log(score + "点:合格");
    }
    else
    {
        Debug.Log(score + "点:不合格");
    }
}

() の中の int score が、「整数を一つ受け取って、score という名前で使います」という意味です。

呼び出す側はこう書きます。

ShowResult(85);
ShowResult(42);

ShowResult(85) と書くと、85 がメソッドの中の score に入って処理が進みます。

ShowResult(85);
        ↓ 85 が渡される
void ShowResult(int score)   ← score の中身は 85

引数は、

処理をするときに渡す情報

と考えてください。

7. 戻り値 ― メソッドから返ってくる結果

ここで、3章の「合否を判定する」を思い出してください。

「結果を表示する」は、表示したら終わりです。一方、「合否を判定する」は、判定した結果(合格か、不合格か)を呼び出した側に教えてほしい処理です。

この「メソッドから返ってくる結果」が戻り値です。

点数を渡す(85)
↓
合否を判定する
↓
結果が返ってくる(合格)

C#では次のように書きます。

bool IsPassed(int score)
{
    return score >= 60;
}
  • メソッド名の前の bool は、「このメソッドは true(はい)か false(いいえ)を返します」という意味です
  • return の後ろに書いたものが、呼び出した側に返されます

呼び出す側では、返ってきた結果を受け取って使います。

bool passed = IsPassed(85);   // passed には true が入る

では、これまで何度も出てきた void は何だったのでしょうか。

void は「何も返さない」という意味です。ShowResult は表示して終わりなので、返すものがありません。だから void だったのです。

メソッド役割返すもの
IsPassed合否を判定するbool(合格か不合格か)
ShowResult結果を表示するなし(void)

3章で「判定する」と「表示する」を別の名前にしたのは、ここにつながっています。

8. Unityで書いてみよう

ここまでの内容を、実際のUnityのスクリプトで確認します。

準備

  1. シーンに空のGameObjectを作る(Hierarchyで右クリック →「Create Empty」)
  2. ScoreChecker という名前でC#スクリプトを作る
  3. 作ったスクリプトを、空のGameObjectにドラッグしてアタッチする

メソッドを使わずに書いた場合

まずは、すべてを Start の中にベタ書きしてみます。

using UnityEngine;

public class ScoreChecker : MonoBehaviour
{
    void Start()
    {
        int scoreA = 85;
        if (scoreA >= 60)
        {
            Debug.Log("Aさん:合格");
        }
        else
        {
            Debug.Log("Aさん:不合格");
        }

        int scoreB = 42;
        if (scoreB >= 60)
        {
            Debug.Log("Bさん:合格");
        }
        else
        {
            Debug.Log("Bさん:不合格");
        }

        int scoreC = 60;
        if (scoreC >= 60)
        {
            Debug.Log("Cさん:合格");
        }
        else
        {
            Debug.Log("Cさん:不合格");
        }
    }
}

動きはしますが、ほぼ同じコードが3回並んでいます。合格ラインを70点に変えたくなったら、3か所すべてを直さなければなりません。一か所でも直し忘れたら、その人だけ判定がずれてしまいます。

メソッドに切り出した場合

「分ける・まとめる・名前を付ける」を使って書き直します。

using UnityEngine;

public class ScoreChecker : MonoBehaviour
{
    void Start()
    {
        ShowResult("Aさん", 85);
        ShowResult("Bさん", 42);
        ShowResult("Cさん", 60);
    }

    // 合否を判定する
    bool IsPassed(int score)
    {
        return score >= 60;
    }

    // 結果を表示する
    void ShowResult(string name, int score)
    {
        if (IsPassed(score))
        {
            Debug.Log(name + ":合格");
        }
        else
        {
            Debug.Log(name + ":不合格");
        }
    }
}

ShowResult の引数は、name と score の2つになりました。このように、引数はカンマで区切って複数渡せます。

Start の中を見てください。何をしているのかが、日本語の文のように読めます。

Aさんの結果を表示する
Bさんの結果を表示する
Cさんの結果を表示する

そして、合格ラインを変えたいときは IsPassed の中の一か所を直すだけです。

長いStartの中身をShowMessageメソッドに切り出し、Startが短く読みやすくなった比較
メソッドに切り出すと、呼び出す側のコードが読みやすくなる

再生ボタンを押すと、Consoleウィンドウに次のように表示されます。

Aさん:合格
Bさん:不合格
Cさん:合格

ゲームのコードでも、考え方は同じです。たとえば Update の中に書いた左右の移動処理を MovePlayer というメソッドにまとめると、Update は「プレイヤーを動かす」と一目で読めるようになります。

Updateの中に書いた左右の移動処理を、MovePlayerというメソッドにまとめてUpdateから呼び出す比較(Input System使用)
Updateの中の移動処理を、MovePlayerメソッドにまとめる

9. 練習してみよう

答えは記事の最後にあります。まずは自分で考えてから確認してください。

練習1

次の行動を一言でまとめてください。

コップを出す
水を入れる
飲む
コップを片づける

練習2

次の2つに、それぞれ名前を付けてください。手順は似ていますが、目的が違います。3章の「合否を判定する」と「結果を表示する」を思い出してみましょう。

【まとまりA】
プレイヤーの体力を見る
体力が0以下か確認する
ゲームオーバーかどうか決める
【まとまりB】
プレイヤーの体力を見る
体力が0以下か確認する
ゲームオーバーかどうか決める
画面に「GAME OVER」を表示する

練習3

次の大きな行動を、細かく分けてください。

学校へ行く

練習4

次のメソッドについて答えてください。

int GetDoubleScore(int score)
{
    return score * 2;
}
  1. 引数はどれですか?
  2. 戻り値の型は何ですか?
  3. GetDoubleScore(30) を呼び出すと、何が返ってきますか?

10. メソッドを書く前に考えてほしいこと

メソッドを作るとき、いきなり

void 〇〇()
{
}

と書き始める必要はありません。先に、次の順番で考えてみてください。

① この何行かは、何をしているのだろう?
② 一言で表すなら、何のためのまとまりだろう?
③ 毎回変わる情報はあるか? → あれば引数にする
④ 結果を呼び出し元に返す必要があるか? → あれば戻り値にする

ここまで決まれば、あとは形に当てはめるだけです。

名前の付け方のコツ

C#(Unity)のメソッド名は、次のルールで付けるのが一般的です。

  • 動詞から始める:ShowResult(結果を表示する)、AddScore(点数を加える)
  • 単語の頭を大文字にする:showresult ではなく ShowResult
  • true / false を返すメソッドは Is〇〇 にすることが多い:IsPassed(合格しているか)、IsGameOver(ゲームオーバーか)

名前を見ただけで何をするメソッドかわかるのが、良い名前です。

まとめ

メソッドがわからないとき、void・引数・return を何度も覚えようとしても、なかなか頭に入りません。

そんなときは、いったんコードから離れて、

分ける
まとめる
名前を付ける

を練習してみてください。

メソッドは、

細かい処理をひとまとまりにして、その仕事に名前を付けたもの

です。

そのうえで、

  • 毎回変わる情報を渡すのが引数
  • 処理の結果を返すのが戻り値
  • 何も返さないときは void

と整理すれば、コードの形も自然に読めるようになります。

最初からすべてを覚える必要はありません。まずは「このまとまりに名前を付けるなら?」と考える習慣から始めてみましょう。


練習の解答例

練習1

「水を飲む」

練習2

  • A:「ゲームオーバーか判定する」(英語なら IsGameOver)
  • B:「ゲームオーバーを表示する」(英語なら ShowGameOver)

Aは「決める」ところで終わっているので判定、Bは表示までしているので表示です。3章の IsPassed と ShowResult と同じ関係になっています。

練習3

たとえば次のように分けられます。

起きる
着替える
家を出る
駅へ行く
電車に乗る
学校へ着く

分け方に正解は一つではありません。「朝ご飯を食べる」を入れても、「電車に乗る」をさらに細かく分けてもかまいません。

練習4

  1. int score
  2. int(整数)
  3. 60
訪問数 6 回, 今日の訪問数 1回

広告