カテゴリの最新記事

【イカ焼き備忘録】2-0.ものすごく大雑把なプログラムの説明

前【オブジェクトの配置】

では、前回配置したオブジェクトを実際動かす……前に、ものすごく大雑把にプログラムの知識を頭に入れておきましょう。
少しでもプログラムについてかじったことがある方は見なくても問題ないです。
プログラミングはしたことなくても、RPGツクールとか触ったことある人も見なくて大丈夫です。
変数の使い方知ってれば大丈夫な程度。

ちょっとぐらい書き方を間違えてもエラーが出るだけなのです。
一行ずつ書いていって、出たエラーを都度直せばいいだけのことです。
足りない技術は時間でカバーしましょう。
正直私も人に説明できるほどの知識は持ち合わせていません(じゃあなんでこんな記事書いてる)。

とりあえず今回はUnityは使わず、実際のプログラミングとも違う、ぼんやりとした抽象的な話だけします。

変数ってなんだ

(※間違った認識も多いかと思います。あくまで私の認識ということで)

プログラミングを行うにあたって、必ず知っておかなければならないものが”変数”です。
そして変数さえ知っておけばある程度のことができるようになります。便利ですね。

変数は文字の通り”変わる数値”のことです。
足したり引いたり、または全く違う数値に変更する予定のあるものは全て変数として使います。

と、文字だけで書いてもわかりにくいので例え話をしましょう。
目の前に”いかロールプレイングゲーム”があるとします。
ステータス画面を開くとキャラクターの名前や攻撃力、足の速さなどが表示されます。


(nameという変数に名前が、attackという変数に攻撃力が。speedという変数に足の速さが書かれている)

ゲーム中において攻撃力や足の速さは鍛えられるほど高まる、つまり”変わる数値”なので変数です。
名前に関しても、プレイヤーが自由に名前を決められる作品だったりすれば変数にしておかなければなりません。
変”数”とは書いてありますが、数値だけではなく文字だってなんだって入るのです。

変数の宣言と型

(UnityにはUnityScriptとC#、二種類の言語が使えますが、C#を使っていきます)

変数がどういうものかはわかった!じゃあ早速プログラミングをしていこう!!
「変数nameの中身を”いかちゃん”とする!!」
と勇ましくコードを書いても、Unityちゃんは残念ながら理解してくれません。
Unity「そもそも”name”ってなんだよ」
とエラーを返されてしまいます。
変数を扱う前には”宣言”という行為が必要になります。

では変数を宣言する実際のコードが以下になります(イカだけに

string name;
name = "いかちゃん";

一行目で「string型のnameという変数が宣言された」ことになり、
二行目で「nameという変数にいかちゃんを代入した」という意味になります。
型というのはどういった変数を扱うかを決めるもので、とりあえずはstring型とint型とfloat型とbool型の四つを覚えておきましょう。

string型:文字を入れるもの
int型:整数を入れるもの
float型:小数を使う数値を入れるもの
bool型:真(true)か偽(false)のどちらかが入るもの。いわゆるフラグ

こういった型と変数名を宣言してからでないと「そもそも”name”ってなんだよ」というエラーを返されることになってしまいます。
また、変数同士で計算するような場面も出てくるかと思いますが(例えば、体力-攻撃力とか)、
計算する場合はお互いの変数が同じ型でないと基本的にはできません。
名前-攻撃力とかどうやって計算するんだ、という話ですよね。

拙い説明でしたが、なんとなく変数はこんなものだ、というのがわかっていただけたら嬉しいです。
これら変数を足したり引いたり、「もし変数hpが0になったとき、ゲームオーバー画面を表示する」といったプログラムを組んでいくことで段々とゲームらしきものを作り上げることができるようになるのです。

余談ですが、先ほど書いた変数の宣言と代入のプログラムは大抵の場合において一行で書かれます。
string name = “いかちゃん”;
この一行で変数の宣言と代入を同時に行うことができます。

関数ってなんだ

関数は正確なところでは深い定義や意味があるのでしょうが、”イカを焼く”を作る上では難しいことを考える必要はありません。
「関数は一連の行動をひとまとめにしたものである」
ぐらいの認識で大丈夫です。

特定の行動手順を関数にまとめておくと、色々なことが楽になります。
例え話ばかりで申し訳ないのですが、目の前に”二足歩行するねこプログラム”があるとします。
この二足歩行するねこは「右足を前に出し、左足を前に出す」という手順を踏むことにより前に歩くことができます。
これをプログラムにすると

右足 前へ
左足 前へ
右足 前へ
左足 前へ
右足 前へ……

というプログラムになります。
さて、急な思いつきですが、二歩歩いたらねこが休憩するプログラムに変えたいと思いました。
二歩歩いたら休憩するようにプログラムを書き換えます。

右足 前へ
左足 前へ
休憩
右足 前へ
左足 前へ
休憩
右足 前へ……

こうしてプログラムを書き換えました。
ふと、急にアイデアが浮かびました。
「休憩後に背中を伸ばす動作をしてから歩き始めるようにしよう」
またプログラムを書き換えます。

右足 前へ
左足 前へ
休憩
伸び
右足 前へ……

……これが短いプログラムならいいでしょう。
しかし、もしも「ねこが1000歩歩くムービーシーン」を作っているとしたらこのコードは現実的でしょうか?
思いつきで何か違う行動を入れる度に1000歩分全てのプログラムを書き直していかなければなりません。
書き直していく中でタイプミスなどでエラーが発生する可能性もあり、その場合膨大なコード行数の中からたった一行のエラー部分を特定しなければなりません。
エラーは起こらなくても「右足、左足」という順番で歩くのに、ある部分だけ「左足、右足」の順に歩いてしまう場面があったとすれば、それを直すためにまた膨大なコードと睨めっこすることになってしまいます。
これはあまりにも非現実的です。

さて、このプログラムの場合、二足歩行の猫は常に規則的に動いています。
そのため、その規則的な部分を関数としてまとめてしまいましょう。
そうして出来上がったプログラムのイメージはこんな感じになります。

関数 ねこを歩かせる
「右足 前へ
左足 前へ
休憩
伸び」
1000歩歩くまで[“ねこを歩かせる”を実行]

とてもスマートなプログラムになりましたね。
もしも「やっぱり伸びの動作は要らないな、削除しよ~」って思ったとしても、関数の中の”伸び”を消すだけで済むのです。


(同じ動作を繰り返すときは、関数を使うのが良いですね)

引数ってなんだ

関数を使うことによって、ねこが二足歩行する動作をひとまとめにすることができました。
しかし、再び急なアイデアが浮かんできて、またコードを書き直すことになりました。
「ねこが歩く速度を都度変化させたい」
さて、どのようにコードを書けばいいでしょうか。

段々遅くなっていく、等の規則性のある動作であれば、今ある関数の中に最後に”ちょっと減速する”といったコードを書き足せばきっと実現できると思います。
しかし
「最初は普通の速さで、次にちょっと遅くなって、最後にマッハ5の速度で歩くねこにしたい」
という感じで不規則な動作をさせたい場合には、そういった方法では実現できません。

「じゃあ”普通に歩く関数”と”ゆっくり歩く関数”と”マッハ5で歩く関数”を作ろう」
これは一つの正解ではあります。
が、この書き方だと違う速度で歩かせたくなったときに、その都度関数を作っていかねばなりません。
マッハ1で歩く関数とマッハ2で歩く関数とマッハ3で歩く関数と……
これではやはり、膨大な量のコードになってしまい、なんというか面倒に思えますね。

そこで出てくるのが「引数」です。
引数とは、関数を実行する際に、その関数に渡してあげる数値のことです。
と文字で書いてもよくわからないので、もう一度”二足歩行するねこプログラム”を例にとってみましょう。

まずは引数を使わない二足歩行ねこプログラムから見ていきましょう。

関数 速度1.0で二足歩行(){
 速度1.0で右足を前へ
 速度1.0で左足を前へ
}

関数 速度2.0で二足歩行(){
 速度2.0で右足を前へ
 速度2.0で左足を前へ
}

速度1.0で二足歩行 を実行();
速度2.0で二足歩行 を実行();

(※{ }で括られた部分が関数を実行した際に実行されるプログラムとなります)
こういった方法でも歩く速度は変えられると思います。
ですが、速度を変えようとする度に関数を増やしていくのはあまりスマートではないように思えます。

そこで、引数を使ってみましょう。

関数 二足歩行 (float speed) {
 速度speedで右足を前へ
 速度speedで左足を前へ
}

二足歩行 を実行(1.0);
二足歩行 を実行(2.0);

どうでしょうか、ずいぶんすっきりとしたコードになりましたね。
ここで()内に書いたものが”引数”と呼ばれるものです(引数を使わない場合でも()は書く必要があります。)
二足歩行を実行(1.0)と書くことで、関数側に書かれた変数が宣言され、その変数に(1.0)が代入されることになります。この場面では、float型のspeed変数に1.0が代入されたことになります。
この二つは動作自体は全く変わりないコードですが、コードの短さ、わかりやすさは全く異なるものだというのが分かったと思います。


(動作は同じだけど速度だけ違う、動作は同じだけど攻撃力だけ違う、などといった場合に引数は役立ちます)

変数を扱える範囲

変数と関数について覚えることができたので、最後に変数を扱える範囲について簡単に説明しておきましょう。
変数は原則的に宣言した関数の中でしか使うことができません。
どういうことか、以下に示します。
今までは抽象的なコードみたいな何かを書いていましたが、今回は最後ですので実際にUnityで動かせる書き方で書いてみたいと思います。

public class Ikawotabeta : MonoBehaviour { //この{}で囲まれた範囲が"クラス"ということだけ覚えておけば大丈夫です

 string yakiika = "焼きイカ食べたい";  //string型の変数yakiikaに"焼きイカ食べたい"を代入します

 void Start() { //←Start関数は自動的に実行されます
  Neko(); //関数Nekoを実行
  Ika(); //関数Ikaを実行
  Kansou(); //関数Kansouを実行
 }

 void Neko(){ //関数Neko
  string ko = "10個ぐらい"; //string型の変数koに"10個ぐらい"を代入します
  Debug.Log("ねこ「"+ yakiika + ko + "」"); //ねこ「焼きイカ食べたい10個ぐらい」と画面に表示されます
  string umai = "美味しかった"; //string型の変数umaiに"美味しかった"を代入します
 }

 void Ika(){ //関数Ika
  string ko = "2個ぐらい"; //string型の変数koに"2個ぐらい"を代入します
  Debug.Log("いか「"+ yakiika + ko + "」"); //いか「焼きイカ食べたい2個ぐらい」と画面に表示されます
  string mazui = "不味かった"; //string型の変数mazuiに"不味かった"を代入します
 }

 void Kansou(){ //関数Kansou
  Debug.Log(umai); //美味しかった とは表示"されません"
  Debug.Log(mazui); //不味かった とは表示"されません"
 }
}

一番最初にクラス内で宣言したyakiikaは、クラスの{ }内に含まれている関数NekoやIkaの中で扱うことができます。
しかし関数NekoとIka、Kansouは独立している(それぞれの関数の{ }で括られていない)ため、関数Nekoの中で宣言した変数umaiを、関数Kansouの中で使うことはできないというわけです。


(変数を宣言した場所の内側でしか、その変数を使うことができない)

もしもこのコードを直すならこんな感じになるでしょうか。

public class Ikawotabeta : MonoBehaviour { //この{}で囲まれた範囲が"クラス"ということだけ覚えておけば大丈夫です

 string yakiika = "焼きイカ食べたい";  //string型の変数yakiikaに"焼きイカ食べたい"を代入します

 void Start() { //←Start関数は自動的に実行されます
  Neko(); //関数Nekoを実行
  Ika(); //関数Ikaを実行
 }

 void Neko(){ //関数Neko
  string ko = "10個ぐらい"; //string型の変数koに"10個ぐらい"を代入します
  Debug.Log("ねこ「"+ yakiika + ko + "」"); //ねこ「焼きイカ食べたい10個ぐらい」と画面に表示されます
  string umai = "美味しかった"; //string型の変数umaiに"美味しかった"を代入します
  Kansou(umai); //関数Kansouを、引数にumaiを入れて実行
 }

 void Ika(){ //関数Ika
  string ko = "2個ぐらい"; //string型の変数koに"2個ぐらい"を代入します
  Debug.Log("いか「"+ yakiika + ko + "」"); //いか「焼きイカ食べたい2個ぐらい」と画面に表示されます
  string mazui = "不味かった"; //string型の変数mazuiに"不味かった"を代入します
  Kansou(mazui); //関数Kansouを、引数にmazuiを入れて実行
 }

 void Kansou(string bunsyou){ //関数Kansou
  Debug.Log(bunsyou); //関数Nekoが実行された際には美味しかった、関数Ikaが実行された際には不味かったと表示されます
 }
}

これを実行すると、

ねこ「焼きイカ食べたい10個ぐらい」
美味しかった
いか「焼きイカ食べたい2個ぐらい」
不味かった

と表示されることになります。
この修正はほんの一例です。
引数を使わなくても、変数umai、変数mazuiを書く位置を関数内ではなくクラス内に書くという方法でも修正できるはずです。

最後に

正直なところ、上手く説明できていないと思います。
色々と検索してみて、自分でわかりやすいと思う講座を行っているサイトを是非探してみてください。
自分自身間違った認識をしていると思うので、あまり鵜呑みにはしないでくださいませ。

次【移動スクリプトの実装】作成中