今回はメソッドの使い方を解説していきます。メソッドをうまく使えるようになるとプログラミングを更に便利にしていけるのでぜひ覚えていきましょう。
↑の動画でも解説しています。プログラムの流れは動画の方が見やすいと思うので、是非ご活用ください。
この記事は本のように順を追って解説しています。この記事は途中のページになります。
この記事を見ていて、現在の状況がわからない場合や忘れてしまった事などが出てきたら↓のリンクから目次ページへ飛べますので立ち戻って見てください。
<メソッドを使って便利にプログラミングしよう>
メソッドとは
さて、今までの解説でStartとUpdateはメソッドというもので、Unity側から呼ばれて処理を行うものだよという風に言っていました。
今までの解説はこのページの↑の方にある目次ページを参照してください
Startはスクリプトが有効になったときに1回、Updateは毎フレーム呼ばれて、その中に命令を書いてプログラムを実行していました。
このようにメソッドというのは何かから呼ばれて実行されます。
そして、メソッドが呼び出された時中に書いた処理が実行されます。
このように、何かから呼ばれてそこに書かれている処理を行うので、メソッドはclass(設計図)に書かれた一個一個の機能と、例える事ができると思います。
プログラムを作るという事は、1個1個の機能を持ったパーツを作って、それらを組み上げていくイメージを持ってもらえればと思います。
その1個1個の機能がメソッドです。
このメソッドを使えるようになると、とても便利です。
StartとUpdateはUnityが自動で作ってくれていましたが、今回は自分で作ってみましょう。
メソッドを自分で作ってみよう
メソッドの作り方は
返り値 名前 (引数)
{
}
です。よくわからないと思うので実際にやってみましょう。
↑の
void aaa()
{
}
というのが自分で作ったメソッドです。
voidというのは以前出てきたと思いますが、何も返さないよという意味です。返すって何?って話ですが、後で説明するので今はスルーしましょう。
「aaa」っていのがメソッドの名前です。変数の時もそうでしたが、名前は何でも構いません。ただし、既に使われているものは使用できません
Unity側が使っている名前、C#側が使っている名前も使えません。
その後( )で囲んでいます。ここには引数と呼ばれるものが入ります。
引数が必要ない場合は、()の中に何も書かなければ引数はなしになります。
とりあえず、順に解説していきますのでは、まずは引数なしでやってみましょう。
メソッドに機能を持たせよう
メソッドを作成する事ができたら、メソッドに機能を持たせましょう。
{ }で囲んだ中に機能を書いていきます。
と言っても普通に{ }の中に命令を書いていくだけです。
とりあえず、今回はお試しという事でログを表示されるだけの機能を作ります。
void aaa()
{
Debug.Log(“aaaが呼び出ばれた”);
}
これでaaaというメソッドはログを表示するという機能を持ちました。
メソッドを呼び出してみよう。
メソッドは作成するだけでは意味がありません。
StartとUpdateはUnity側から呼び出されていました。
自分で作ったメソッドは自分で呼び出してあげる必要があります。
ではメソッドを呼び出してみましょう。
Startにaaa();と書いてあるのがわかるでしょうか。
これがメソッドの呼び出しです。
こうする事で、StartがUnity側から呼び出される→aaaがStartから呼び出されるという形になります。
このスクリプトをゲームオブジェクトに貼り付けて再生するとコンソールウィンドウに「aaaが呼ばれた」と表示されます。
このように、メソッドは呼び出されると実行されます。
メソッドの処理順
さて、メソッドが呼び出されると実行されるのはわかりましたが、呼び出した時の処理の順番がどうなるのかみてみましょう。
Start内で関数aaaを呼び出していますが、この関数は一体どういう順番で処理されるかをみていきましょう。
答えは↑のようになります。
Startの処理が終わってからaaaを処理するわけではなく、Startでaaaを呼んだ瞬間に処理されている事がわかります。
そしてメソッド内でメソッドを呼び出すと、呼び出した箇所でメソッドの処理が終わってから次の処理へ進みます。
これは(基本的に)1フレーム内で行われます。
メソッドは何度でも呼べる
さて、何となくメソッドの基本的な挙動について理解できたところで次はメソッドの最大の利点を生かしてみましょう。
それは何度でも、いろんなところから呼べる点です。
まぁ、↑の例だと適当に書いたので大して意味がないですが、このように、いろんなところから何度でも呼べる点が利点になります。
この利点というのは、いろんな共通の処理をする際にとても便利です。
例えばゲームを作る際、何かボタンを押した際にどのボタンでも同じ処理をしたい(演出やSEを鳴らすなどをしたい)場合、全部のボタンに同じ処理を書いていては大変です。
共通で使用する処理をメソッドにして呼び出せるようにすれば1箇所に書いておけばよく、たくさんいろんな所に同じ文を書く必要が無くなります。
コピペすればいい話と思うかもしませんが、プログラムがごちゃっとしますし、内容を変更したくなった場合、全箇所修正する必要があったものが1箇所修正すればよくなります。
また、メソッドにしてまとめておく事でプログラムが非常に読みやすくなります。(後で自分のを読み返す時に忘れてしまう事が多々あるので読みやすくしておくのは有用)
このように様々な命令をメソッドにすることによって1つ1つの機能にしてパーツ化する事で、共通で使える便利なものになるのです。
変数のスコープに気をつけてメソッドを何回も呼んでみよう
さて、↑の例では簡単な例でしたが、ちょっと応用したものを解説してみたいと思います。
↓の例をみてみましょう。
↑の場合「変数b」はメソッドの外に書いてあるためスコープ({ }の範囲)はこのクラス全体です。
aaaは呼び出されるとbをプラス1しますが、bがクラス内で有効な為プラス1した値は保存されます。
そのため、何回もaaa()を呼び出すと呼び出されたタイミングでbがプラス1されます。
というわけで、↑の例ではコンソールに「5」と表示されます。
このような感じでクラス内共通のデータを利用する事で中身を更新するような使い方をすることもできます。
<引数を使って更に便利にしよう>
引数とは
引数というのは、メソッドに送るデータの事を言います。
書いた1つ1つの機能にデータを送れる感じです。
↑の解説でクラス内共通のデータを使用する例を紹介しましたが、何でもかんでも共通化してしまうとプログラムがぐちゃぐちゃになってしまいますし、共通にしたくない場合もあります。
そういう時には引数を使いましょう。これを使う事で、メソッドは更に便利になります。
言うだけではわかりづらいと思うので、とりあえずやってみましょうか。
引数の書き方
引数の使い方はメソッドの書き方での
返り値 名前 (引数)
{
}
( )の中身に書きます。
今までは( )の中は何もなしとしていました。
ではこの中に何か引数を入れてみましょう。
この中での引数の書き方は
(型名 名前)
と書きます。
要するに、メソッドに対して、指定した型のデータを送る事ができます。そして、そのデータに名前をつけている感じです。
↓のように書きます。
void aaa(int b) { }
こう書く事で、メソッドaaaはint型の名前bというデータを受け取る事ができます。(名前は適当です)
なんか変数みたいですが、まさにその通りで、このメソッドの中だけで使える変数になります。
また、呼び出し側はデータを送ってあげる必要があります。
ちょっと引数を使ってみましょうか。
↑のような感じで書きます。
aaaを呼び出しているところで(1)と入れています。これで「1」のデータを渡しているわけです。
これはメソッドが受け取るデータを「int」と定義している為、整数を入れることになります。その為1を入れています。
これを実行するとコンソールに「1」と表示されます。
↓のようにすると
コンソールには「1」「2」「3」と表示されます。
引数であるbの中身は呼び出された時に渡されたデータになるわけです。
変数のスコープに気をつけて引数を扱ってみよう
さて、引数はメソッドの中だけで使える変数になると解説しましたが、↓の場合はどうなるでしょうか?
Start内でもaaaの引数でも同じ「b」と言う名前の変数を使っています。
さて、これを実行するとコンソールには「0」と表示されます。
御察しの通り、スコープ({ }の範囲)が違うからです。
Startの中のint bはStartの中でのみ有効で、aaaのint bはaaaの中でのみ有効になります。
同じ名前でもスコープが違えばそれは違うものです。
まぁ、ややこしいので基本同じ名前にはなるべくしないようにするのが普通ですが
ではスコープを被らせてみるとどうなるのでしょう?
これを実行すると
ゼロになります。
同じ名前の変数でスコープが被っている場合は、スコープが狭い方が優勢されます。
同じスコープ内で、同じ名前の変数を定義するとエラーになりますので注意してください。
引数を複数にしてみよう
さて、↑の例では引数は1つでしたが、複数定義することもできます。
(型名 名前, 型名 名前, 型名 名前・・・・)
という感じで「,」で区切る事で引数をたくさん書けます。
ちなみに最大で65536個書けるらしいです。書かねーよ
例えば
void aaa(int a, int b, int c) { }
みたいな感じですね。
これもStartから呼び出して、Debug.Logで何か表示させてみましょう。
こんな感じです。Startでaaaを呼び出していますが、今度は引数が3つになったので呼び出し元でaaa(1,2,3)というように3つデータを渡しています。
データを3つ渡されて「a = 1,b = 2,c = 3」になるので、ログに表示されるのは1+2+3で「6」ですね。
このように複数のデータを渡して取り扱うこともできます。
<返り値(戻り値)とは>
返り値(戻り値)を返してみよう
さて、以前「voidで返り値を返しませんよ。」とよくわからないことを言っていましたが、実はメソッドは値を返すことができます。
メソッドは1個1個の機能なので、計算した結果や処理した結果を呼び出し元に返して結果を知らせることができるのです。
これを返り値、もしくは戻り値といいます。
では実際にやってみましょう。
voidは「何も返さない」という意味になるのでここを変えましょう。
まずはvoidのところを型にします。
そして、返したい結果をreturnで返します。
やってみるとこんな感じです。
voidだったところがintになっています。そしてreturnというのが書かれています。
この場合もログには6と表示されます。何を行なっているかというと
①Startでaaaを呼び出します。a=1,b=2,c=3を代入しています。
②aaaの中でa+b+cを計算します。つまり6です。
③aaaはreturnで6という数字をint型で呼び出し元に返します。
④Startでaaaを呼び出した所に6という数字がint型で返ってきます。
⑤返ってきた6をint型のdに代入します。
⑥ログにdを表示します。>6と表示されます。
こんな感じです。
このようにメソッドにデータを渡して、中で処理した結果を呼び出し元に返すことができます。
そして↑の例では返ってきた結果を変数に代入しているわけです。
メソッドに引数で元となる物を与えて、中で処理して返すという手法はとても便利でよく活用すると思うので覚えておくといいと思います。
returnについて
returnはデータを返すものです。
メソッドの返り値が定義されているときは絶対に書かなくてはいけません。
反対に返り値がvoidと書いた時は何も返さないという意味になるのでreturnは書く事ができません。
そして、returnで値を返すとそのメソッドは処理が終わったとみなされます。
↑のように書いた場合、コンソールには1とは表示されますが、aaaとは表示されません。
何故かというと、returnで値を返しているのでそこで処理が終わったとみなされてDebug.Log(“aaa”);が処理されずに終わります。
メソッド内にあるデータを返した場合
メソッド内にまたスコープが違う同じ名前の変数を用意してみました。
この状態で再生するとどうなるでしょう?
同じ変数名bですが、スコープは違います。しかしデータは返しています。
・・・
はい、御察しの通り0になります。
やはりスコープが違うのでaaaの中でブラスしたところで呼び出し元のbには影響がありません。
では↓の場合はどうでしょう?
これは答えは0になりません。5になります。
スコープが違うのに何故?という話ですが、この場合は
b= aaa(b);
としている為、返ってきたデータを変数に代入しています。
この為、最初b(中身0)をaaaに渡します。すると「1」が返ってきます。それをbに入れます。するとbの中身は「1」になります。
またb(今度は中身1)をaaaに渡します。すると「2」が変えてきます。それをbに入れます。するとbの中身は「2」になります。
これを繰り返す事でbは5になるわけです。
このように返ってきた値をちゃんと受けとる事でデータをうまく取り扱うこともできます。
<まとめ>
さて、今回の解説をまとめると
次はちょっとプログラムらしいことをやってみたいと思います。