【Unity】C#の基本構文『演算子』

 

演算子について

C#入門 基本構文第2回「演算子」。
今回は『演算子』についての解説になります。

 

 

もくじ

1.演算子とは
2.演算子の種類
3.初心者が知っておくべき演算子

 

 

演算子とは

『演算子』とは、プログラミングにおいて式などの演算に用いられる記号のこと

+、-のようにプログラミングの中で使われる記号のことを「演算子」といいます。

 

 

演算子の種類

演算子には、以下のようなものがあります。

 算術演算子: +  * / %
 代入演算子: = += -= *= /= %= &= |= ^= <<= >>=
 比較演算子: < > <= >=
 等値演算子: == !=
 論理演算子: && || ! 
 ビット演算子: & | ^ ~ 
 シフト演算子: << >>
 三項演算子: ?:
 インクリメント: ++ 
 デクリメント: --

 

 

初心者が知っておくべき演算子

では、初心者が知っておかなければならない最低限の演算子を上げていきます。

 

四則演算を行うための算術演算子「+」「」「*」「/」「%」は必須です。

基本的な使い方は、小学校で習った四則演算の通り(記号が一部違っていますが)なのですが、

+」には、「加算」以外にも「文字連結」の意味があり、しっかり使い分けられるようにしておく必要があります。

また、除算に関する「/」と「%」の2つ違いについてもしっかりと理解しておいてください。

 

代入演算子である「=」と、その複合型である「+=」「-=」「*=」「/=」「%=」の四則演算に関する代入演算子も理解しておいてください。

複合型は、計算部分が異なるだけで、基本的にはすべて同じ使われ方がされるため、「+=」の1つを理解しておいていただければ、ほかの複合型の代入演算子も使いこなせるでしょう。

 

値を比較するために用いられる比較演算子「<」「>」「<=」「>=」、等値演算子「==」「!=」も必須です。

これらは、if、for、while文の条件判定の際に用いられる演算子になります。

 

論理演算子「&&」「||」「!」も必須です。

「&&」「||」は、if、for、while文で複数の条件文を使用するときに用いられ、「!」に関しては、条件文を否定するときに用いられる演算子になります。

 

インクリメント「++」とデクリメント「--」に関しても覚えておく必要があります。

これらは、for文の反復子として頻繁に目にすることになると思います。

 

まとめておくと、

 算術演算子: +  * / %
 代入演算子: = += -= *= /= %= 
 比較演算子: < > <= >=
 等値演算子: == !=
 論理演算子: && || ! 
 インクリメント: ++ 
 デクリメント: --

上記以外の演算子に関しては、必要になったら調べる、で良いと思います。

 

【Unity】C#の基本構文『変数について』

 

変数について

C#入門 基本構文第1回「型と変数」。
今回は、『変数』についての解説になります。

 

 

もくじ

1.変数とは
2.変数の宣言
3.変数の初期化
4.変数の初期化は必須?
5.変数宣言のいろいろ
6.変数の使い方
7.変数の有効範囲(スコープ)
8.変数名について
9.変数の有効期限

 

 

変数とは

『変数』とは、数値や文字といったデータを保持しておくための”入れ物”のこと

コードを書いていると、計算結果や取得した文字列など、データを一時的に保持しておきたい場合がどうしても出てきます。

「頭の中で計算しているときに、途中の計算結果をノートにメモしておく」そんなイメージで、一時的に値を記憶しておくために「変数」が利用されます。もちろん一時的な場合だけでなく、ゲーム起動中ずっと値を保持ておく場合にも「変数」を使います。

 

もっとかみ砕いて、もっと具体的に説明します。

 

このようなコードを書いた場合、これは単純に「5+3」の計算が行われるだけなのです。

何言ってるの?と思われるかもしれませんが、

「5+3」の “計算が行われるだけ”のコード” であり、何の意味も持たないコードであると言いたいのです。

 

何の意味も持たない” とはどういうことかというと、「5+3」という計算をした以上、

その計算結果である「8」を利用しないと意味がないですよね、ということです。

利用しないのであれば、何のために計算したの?となります。

計算結果を利用するからこそ、計算をする意味があるわけです。

 

意味のあるコード“にするためには、

「5+3」で計算した結果を利用するために、値を保持しておかなければなりません。

もうお分かりですね。ここで登場するのが「変数」です。

「変数」という入れ物を用意して、計算結果である「8」を入れて値を保持しておきます。

そうすることで、変数に入れた「8」という値を後から利用することができるようになるわけです。

 

これが「変数」の使われ方になります。

「変数」というのが、”値を保持しておくための入れ物”だということがわかっていただけたかと思います。

 

 

変数の宣言

プログラミングの中で、値を保持したくなったとき、上記で説明したように「変数」に値を入れておくわけですが、その時にまず、「変数を宣言する」必要があります。

「変数を宣言する」とは、値を入れておくための入れ物を用意する、ということです。

 

変数の宣言は、このように書きます。

“int”が「型」で、”count”が「変数名」になります。

 

「型」では、その入れ物のデータのタイプを指定してあげます。

今回の場合は、int型を指定したので、この変数には “整数” しか入れることができなくなります。

このように、その変数に入れることのできるデータを指定するのが「型」になります。

 

「変数名」とは、その変数の名前です。

たくさんの変数を区別するためにつける名前で、

すでに使われている名前以外であれば、好きな名前を付けることができます。

 

「変数の宣言」とは、型を指定し、名前を決めて、”入れ物”を用意すること

 

「count」という整数の入れ物が用意できたので、

このように、7という整数値を”count”に保存しておくことができるようになりました。

 

初心者メモ

 値を代入する(入れる)ときには、「=」を使用します

中学生のときに、変数というものが出てきて、X = 7 という風に Xに値を代入したことがあるかと思いますが、それと同じですね。

countに7という値を代入する場合には count = 7; と記述します。

 

また、上記コードを見てもらうとわかるのですが、コードの終わりには、「;」を忘れずにつけてください。

「;」は、このコードはここで終わりという印になっています。

初心者メモ

 コードの終わりには「;(セミコロン)」を付ける

 

 

変数の初期化

変数を使う場合には、「変数の宣言」を行った後、最初に初期化を行う必要があります。
変数を宣言して入れ物を用意しましたが、その入れ物に最初の値を入れておいてあげるわけです。

あるいは

このように宣言と初期化をまとめて行うこともできます。

これで「count」という入れ物(変数)を7という整数で初期化することができました。

整数の入れ物であるint型で変数を宣言したので、整数しか入れることができないのは先ほど説明しましたね。

 

初心者の方への注意点ですが、

プログラミングのコードというのは、例外を除いて必ず上から下へと実行されていきます。

ですので、

という順番で記述することはできません。

必ず

と変数を宣言してから、

と変数に値を代入するようにしてください。

 

初心者メモ

・コードは上から下へと順に実行される

 

 

変数の初期化は必須?

変数の初期化を行わなかったからと言って、エラーになるわけではありません。

ですが、1度も値を代入していない変数を使用するとエラーが起こる可能性があります。

1度も値を代入していない変数には、どのような値が入っているかわかりません。

その変数を使用してエラーが出る、このような不測の事態を発生させないためにも、

変数を宣言した場合には、初期化する癖をつけておくことが大切だと思います。

 

 

変数宣言のいろいろ

変数の宣言を行う場合、型が同じであればまとめて宣言することができます。

この場合、int型で x, y, z の3つの変数を宣言しました。

 

また、同時に初期化も行うことができます。

 

 

変数の使い方

変数はどのように使うことができるのか。

上記のように整数の入れ物であるint型のcountを用意したのであれば、

そのまま “整数” の代わりとしてcountを使うことができます。

 

具体例を挙げると、

このように x と y の変数を宣言した場合、

x には、2 + 3 の結果である 5 で初期化が行われますね。

y はというと、x + 5 となっています。

x というのは、5 が入っているわけですから、 y = 5 + 5; と言い換えることができます。

よって、y は 10 という整数で初期化されたことになります。

このように、”整数” として宣言した変数であれば、”整数” の代わりとしてそのまま計算式の中で利用することができます。

 

 

変数の有効範囲(スコープ)

変数には有効範囲(スコープともいわれます)というものがあります。

好きな場所に宣言して、好きな場所で使える、というわけではないのです。

 

では、変数のスコープについて解説していきたいと思うのですが、

せっかくUnityの講座ですので、Unityのコードで解説していきたいと思います。

 

 

これは、UnityでC#のスクリプトを作成したときに、最初から記述されているコードです。

コード中の // はコメントを書きたいときに記述するコードです。

// を記述した行でのみ、// より後ろがコメントであることを示しています。

初心者メモ

・コード内でコメントを書きたい場合には、// を記述し、その後ろに書きます

 

上記のコードですが、初心者の方には何が書かれているかわからないかもしれませんが、

今回注目してもらいたいのは、中括弧{ } です。

これは、C#において一つのブロックを表しています。

 

上記のコードを中括弧で色分けをするとこのようになります。

「クラス」という大きなブロックの中に、「関数」という小さなブロックが2つ入った構成になっています。

「クラス」や「関数」に関しては、今回は解説いたしませんが、いずれ記事にしたいと思います。

 

で、肝心の変数の有効範囲である「スコープ」に関してなのですが、

この中括弧自体が「変数のスコープ」を表しているのです。

 

水色のクラスの中で変数を宣言すれば、水色のクラスの中でのみ変数を使うことができ、

黄色の関数の中で変数を宣言すれば、黄色の関数の中でのみ変数を使うことができます。

 

もう少し具体的に解説をすると、

水色のクラスの中括弧内で宣言された変数は、水色のクラスの中括弧内でのみ使うことができます。

ですので、黄色の関数内でも変数を使うことができます

黄色の関数は、水色のクラスの中括弧内にありますからね。

 

では、黄色の関数の中括弧内で宣言された変数はどうかというと、

この変数は、水色のクラスや別の黄色の関数内では使用することはできません

どちらも、変数を宣言した関数の中括弧内には含まれませんからね。

というわけで、変数は宣言する場所により、その有効範囲が決められているということがわかっていただけたかと思います。

 

 

変数名について

スコープの話が出たので、変数名について少し補足しておきます。

変数名は、「他で使われていない名前であれば、自由に付けることができる」という話をしましたが、

“他で使われていない”ということは、要するに同じ名前の変数はダメということなのですが、当然ですよね。

名前が同じならどの変数のことを指すのかがわからなくなりますから。

 

ですが、スコープが異なれば同じ名前の変数を宣言することが可能です。

これは、スコープが違えば同じ名前であっても区別することができるからです。

 

上記の例でいうと、

2つの黄色の関数内でそれぞれ同名の変数を宣言することができます。

また、水色のクラスと黄色の関数で同名の変数を宣言することもできます。

このように、スコープが違っていれば同名の変数を宣言することは可能なのです。

 

 

変数の有効期限

では、変数の値はいつまで保持され続けるのでしょうか。

こちらも、有効範囲と同様に変数を宣言する場所により異なってきます。

クラスの中で宣言すれば、クラスが破棄されるまで値は保持され、

関数の中で宣言すれば、関数を抜ける(関数の処理が終わる)まで値は保持されます。

クラスと関数について解説していないので、よくわからないかもしれませんが、

宣言する場所によって、有効期限も異なってくるということを覚えておいてください。

 

【Unity】C#の基本構文『foreach』

 

『foreach』文とは

コレクションのすべての要素を1つ1つ取得するときに使用する。

 

 

もくじ

1.基本構文
2.具体例
3.Unityでの使用例【子オブジェクトをすべて取得する】

 

 

基本構文

 

スクリプト

※プログラミングは基本的に、すべて半角英数字で記述します。上記では便宜上全角を使用していることをご了承ください。

 

スクリプトの解説

コレクションの要素を1つ1つ変数に格納して、要素の数だけループが行われます。1つ目の要素を変数に入れて1周し、2つ目の要素を変数に入れて1周し・・・というように、要素の数だけループが行われます。

 

コレクションには、配列やリスト、辞書などが使用できます。

 

“continue;”を記述することで、

それ以降の処理を無視して、次のループへと進むことができます。

 

“break;”を記述することで、

foreach文を抜ける(終了させる)ことができます。

 

 

具体例

それでは具体例を見てみましょう。

 

スクリプト

 

スクリプトの解説

int型の配列arrayを用意し、foreach文で配列の要素を1つ1つコンソールへと書き出す、という処理を行っています。

arrayの1つ目の要素であるarray[0]を、定義した変数 i に代入して、foreach文の中に入ります。i の値は0であるので、if文での条件分岐はスルーされ、Consoleに i の値である0が表示されます。

続いて、arrayの2つ目の要素であるarray[1]を、i に代入して、2周目に突入します。このようにarrayの要素1つ1つを読みだして、ループが行われます。

最終的にConsoleに出力されるのは「0,1」となります。

 

 

Unityでの使用例

子オブジェクトをすべて取得する処理です。

 

スクリプト

 

スクリプトの解説

parentObjの子オブジェクトの名前を列挙するスクリプトになっています。

配列の要素を取得するのであれば、for文よりもforeach文を使うほうが簡単ですね。

 

【Unity】C#の基本構文『for』

 

『for』文とは

決まった回数だけ処理を繰り返したいときに使用します。

 

 

もくじ

1.基本構文
2.構文パターン
3.具体例
4.Unityでの使用例【任意座標のオブジェクトを取得する】

 

 

基本構文

 

スクリプト

※プログラミングは基本的に、すべて半角英数字で記述します。上記では便宜上全角を使用していることをご了承ください。

 

スクリプトの解説

「初期化」「条件式」「反復子」の3つをもとに、for文を決められた回数だけ繰り返します。

詳しい話は、具体例のスクリプト解説で行っています。

 

“continue;”を記述することで、

それ以降の処理を無視して、次のループへと進むことができます。

 

“break;”を記述することで、

for文を抜ける(終了させる)ことができます。

 

 

構文パターン

「while」文は以下のような書き方もできます。

 

パターン1

「初期化」「条件式」「反復子」の各要素は省略することができます。

「条件式」のみを書いた場合の例です。

 

パターン2

3つの要素すべてを省略することもできます。
この場合、無限ループすることになります。
これなら、素直にwhile(true)を使ったほうが良いですね。

 

パターン3

「初期化」と「反復子」は複数の要素を書くことができます。
「初期化」を複数書く場合は、for文の外で変数を定義する必要があります。

for(int x = 0, int y = 0; ; ++x, ++y) と、このように書くことはできません。

 

 

具体例

それでは具体例を見てみましょう。

 

スクリプト

例1)基本的な使い方(変数が1つの場合)

 

例2)変数が2つの場合

 

使用されている変数・関数

==:「等しい」,  >:「より大きい」,  <:「より小さい」
i -= 5;:iを-5する(i = i – 5; を省略した形)
++x;:xの値を+1する
--y;:yの値を-1する
Debug.Log(i):UnityエディタのConsoleに i の値を出力する関数

 

スクリプトの解説

最初に、例1をもとにfor文の各要素について解説します。

” for(int i = 10 ;  i > 0 ;  --i) ”

「初期化」の要素となる「int i = 10」では、最初にint型の i を定義して、10で初期化しています。ここで定義した変数 i はfor文の中でのみ利用することができます。

続いて「条件式」の要素となる「i > 0」では、”i > 0″ は「 i が0より大きい」という意味で、これを満たす限りfor文を繰り返すという条件を示しています。

最後に「反復子」の要素となる「 -- i」では、” -- i”は「 i を-1する」という意味ですが、これはfor文が1周終わるごと(次のループの最初)に呼び出されて実行されます。例1では、1周終わるごとに i の値が1ずつ減っていくわけですね。

「反復子」が実行されるのは、1周終わるごとなので、for文開始時の条件判定は、初期化した数値で行われることになります。ですので、初期化に設定した値がすでに条件を満たしていなければ、1度もfor文に入ることなくfor文を抜けることになります。

例1をまとめると、
int型の変数 i を用意して、10で初期化します(「int i = 10」の部分)。i の値が1周するごとに1ずつ減っていき(「 --i」の部分)、i の値が0以下になったとき(「i > 0」の部分)、ループを抜けることになります。

 

では、改めて例1を見ていきましょう。

上記で説明した通り、i の値がループするごとに1ずつ減少していき、 i の値が0より大きい間はループが続きます。

初期の i の値は10なので、10>0と条件を満たしているのでfor文へと入り、if文は満たしていないのでスルーされ、Consoleに10と表示されます。1周が終わったので、i の値は1減って9になり、次のループへと進みます。

2週目も最初は条件判定から行われ、9>0と条件を満たしているので、再度for文の中へ。

これが繰り返し行われ、最終的に「i >0」を満たさなくなった段階でfor文が終了します。結果、出力されるのは「10,9,8,7,6,」となります。

 

続いて、例2を見ていきましょう。

「初期化」に2つの変数がありますね。この場合は、for文内で変数の定義はできないので、for文の外で定義を行っています。

変数 x は1周するごとに+1され、変数 y は1周するごとに-1されていきます。で「x < y」を満たさなくなった段階でfor文が終了します。

x は0から1ずつ増えていき、y は10から1ずつ減っていく。ゆえに、x と y がともに5になったときに「x < y」を満たさなくなるのでfor文が終了します。結果、コンソールに出力されるのは「0,1,2,3,4」となります。

 

 

Unityでの使用例

Raycastを利用した、任意座標のオブジェクトを取得する関数です。
今回のスクリプトでは、レイヤー名がUIとなっているオブジェクトを取得する関数になっています。

 

スクリプト

 

使用されている変数・関数

Physics2D.RaycastAll(_targetPos, new Vector3(0, 0, 1)):
指定座標に存在する全オブジェクトの情報を配列で取得
LayerMask.LayerToName(ray[i].collider.gameObject.layer):
raycastで取得したオブジェクトのレイヤー名を取得
ray[i].collider.gameObject:raycastで取得したGameObject

 

スクリプトの解説

最初に、受け取った座標に存在している全オブジェクトの情報リストを配列で取得しています。for文を使って取得した配列の要素1つ1つのレイヤー名を確認して、レイヤー名が”UI”となっているオブジェクトが存在していればGameObjectを返し、存在していなければnullを返す、といった処理が行われています。

 

【Unity】『当たり判定』でチェックすべき10のポイント
本日のテーマ

Unityで『当たり判定』がうまくいかない方の
チェックすべき10のポイント

 

これで「当たり判定」をマスターしたも同然です。

では、さっそく見ていきましょう。

 

 

10のチェックポイント

 

Check.1

『Rigidbody』がアタッチされていること

どちらか一方のオブジェクトで良いので「Rigidbody」がアタッチされていることを確認してください。もちろん両方のオブジェクトにアタッチされていても問題ありません。

「当たり判定」と「トリガー」の発生には必須です。

 

Check.2

Rigidbodyの「Simulated」にチェックが入っていること画像1image1

Rigidbodyに「Simulated」という項目がありますが、これのチェックが外れていると、物理シミュレーションが行われないので注意してください。

 

Check.3

両方のオブジェクトに『Collider』がアタッチされていること

両方のオブジェクトに「Collider」がアタッチされていることを確認してください。

「当たり判定」と「トリガー」の発生には必須です。

 

「Collider」に関する詳しいことはこちらをご覧ください。
⇒「『Collider』をマスター!

 

Check.4

両方のColliderの『Is Trigger』のチェックが外れていること画像2image2

物理的接触である「当たり判定」を発生させたい場合には、両方のColliderの「Is Trigger」のチェックが外れている必要があります。

逆に、物理的接触がない「トリガー」を発生させたい場合には、少なくとも一方の「Is Trigger」にチェックが入っている必要があります。

 

「Is Trigger」に関する詳しいことはこちらをご覧ください。
⇒「『Is Trigger』が2つを分かつ!

 

Check.5

Colliderのサイズが適切に設定されていること

Colliderは、Scene画面では緑色の枠(初期設定)で表示されます。適切に設定されていることを確認してください。

Colliderのサイズの設定は、EditColliderをクリックしてScene画面で直接設定する方法と画像3image3、下部のOffsetとSizeに直接数値を入力することにより設定する方法があります。画像4image4

 

Check.6

接触を検出するための関数が正しく使用されていること

物理的接触のある「当たり判定」と物理的接触のない「トリガー」では、接触を検出するための関数が異なります。

「当たり判定」では、OnCollisionEnter・OnCollisionStay・OnCollisionExitの『OnCollision』が付いた関数を使い、引数には「Collision」が使われます。

「トリガー」では、OnTriggerEnter・OnTriggerStay・OnTriggerExitの『OnTrigger』が付いた関数を使い、引数には「Collider」が使われます。

 

「当たり判定」を検知したいのに、「OnTrigger」を使用してしまっていることは多々ありますので、今一度確認してください。

 

Check.7

スクリプトが対象オブジェクトにアタッチされていること

「OnCollision」や「OnTrigger」といった関数を利用するために作成したスクリプトは、「当たり判定」あるいは「トリガー」が発生するオブジェクトにアタッチされていないと意味がありません。

まったく関係のないオブジェクトにアタッチしたりしていませんか?

 

Check.8

コンポーネントや関数で、2Dと3Dを混同して使用していないこと

2Dでの接触を判定したい場合には、「Rigidbody2D」「BoxCollider2D」「OnCollisionEnter2D」「Collision2D」「Collider2D」といったように後ろに2Dの付いたものを使います。

3Dの場合は、2Dのついていないものを使用します。

2Dと3Dが混在していないか改めて確認してください。

 

 

1~7で説明した設定に関しては、以下の記事で詳しく解説しております。

「当たり判定」の設定 ⇒「『当たり判定』の設定方法を詳しく解説!

「トリガー」の設定 ⇒「『Trigger』の設定方法を詳しく解説!

 

Check.9

『Layer Collision Matrix』の対象項目にチェックが入っていること

Edit > Project Settings > Physics (あるいはPhysics2D)を開き画像5image5、Inspectorに表示された「Layer Collision Matrix」を確認してください。画像6image6ここのチェックが外れている場合、該当する2つのレイヤー間での衝突は発生しません。

自身が設定しているレイヤーを確認してみてください。

 

それでもうまくいかない場合には、

一度Unityエディタを再起動して確認してみてください。

それでもダメなら、最初からオブジェクトを作り直して設定しなおしてください。

最終手段ですね。

 

 

最後は番外編になります。

オブジェクトの速度が速くなったときに、

オブジェクトをすり抜けてしまう「壁抜け」が発生した場合の対処法です。

 

Check.10

Rigidbodyの「Collision Detection」を「Continuous」に設定画像7image7

「Collision Detection」に関する詳しいことはこちらをご覧ください。
⇒「オブジェクトが壁をすり抜ける!そんなときの対策

 

以上、番外編を含めた「当たり判定」がうまくいかない方がチェックすべき10のポイントでした。

1つのチェックの有無だけで、「当たり判定」が正常に行われなくなります。

チェックポイントを1つ1つ丁寧に確認してください。

必ずや解決への道が開けることでしょう。

 

これで、『当たり判定』でチェックすべき10のポイントの解説を終わります。