Unity C#の演算子の使い方をマスターしよう | Unity入門の森 ゲームの作り方

Unity C#の演算子の使い方をマスターしよう

演算子についての画像 Unity C#入門講座
演算子には色々な種類がある。


Unity入門の森オリジナル本格ゲーム制作講座はこちら
11種類の本格ゲームの全ソースコード公開・画像&動画による解説付き

演算子についての画像

今回の記事では演算子について解説していきます。

演算子は簡単に言うと、足し算、掛け算、引き算、割り算などを意味する記号ですね。

プログラミングする上ではこうした四則演算以外でも演算子を利用することがあります。

以前の記事の中でも既にいくつか使用されてるので、あまり難しく考えずいきましょう。

前回の記事:

Unity C# 変数と型の使い方 宣言や代入・型変換について
前回はコンパイルエラーとその対処法について解説しました。 前回の記事: 今回の記事ではC#の文法についてみていきましょう! プログラミングにおいて最重要な変数と型についてしっかり解説しています。 型については、初心者さんはいきなり全部を理解...

今回の記事では値を計算する時に使用される演算子について見ていきます。


【Line登録者限定のプレゼントもあるよ!】

Unity C#スクリプトで計算を行う方法

早速ですが、次のようなスクリプトファイルを書いてみましょう!。

今回注目してもらいたい部分は2箇所ありますので、順に見ていきましょう!

Sample.Start()の中の+=演算子

まずは、Smaple.Start()の中にあるMeshの色を設定している部分です。

今までのはSample.Colorの値をそのまま設定していましたが、今回のサンプルコードではSample.Color.rの値に0.5f足したものを設定しています。

上の+=が今回の記事で説明する演算子というものになり、+=はそれの右側にある値(右辺値)を左側にある変数(左辺値)に足し合わせる加算演算子になります。

<左辺値> += <右辺値>

左辺値、右辺値と少し難しい言葉が出てきましたが、プログラミングの専門用語としてよく使われるものになります。

言葉として説明すると難しく感じますが、単純に変数に値を足し合わせる時は+=を使うと覚えていただければ大丈夫です。

Sample.Update()の中、*演算子と=演算子

次はSample.Update()の中にあるTransform.positionの値を変更している部分です。

こちらも以前のものはSample.Valueの値を使ってTransform.positionを変更していただけですが、今回のサンプルコードではSample.Valueの値に0.1を掛けたものを使っています。

上の*が演算子で、*は掛け算を表しています。*演算子は左辺値に右辺値を掛ける乗算演算子になります。

<左辺値> * <右辺値>

*演算子自体に変数を変更する機能はないので注意して下さい。

ですが、サンプルコードを実行するとしっかりTransform.positionの値が変更されてますが、これは=演算子のおかげになります。

=演算子自体は以前の記事にも出てきました。代入演算子と呼びます。

使い方はこれまで見てきた中でなんとなくわかるかと思いますが、左辺値に右辺値を設定(代入)する演算子です。

<左辺値> = <右辺値>

といった形で使います。

演算子とは

ここまで上のサンプルコードの中で使われている演算子について見てきました。

演算子は値に対する操作を表しており、次のものがC#では用意されています。

  • 代入演算子
  • 算術演算子
  • 比較演算子
  • 論理演算子
  • 条件演算子

演算子は基本的に次の形式をとります。

  • 単項演算子 -> 「<演算子> <値>
  • 2項演算子 -> 「<左辺値> <演算子> <右辺値>

代入演算子

代入演算子はその名の通り、代入を行う演算子になります。ここまで何度も使われている演算子です。

代入演算子は2項演算子の形をとります。「<左辺値> = <右辺値>

  • =
代入演算子の実行結果の画像

上のサンプルコードの変数の値を出力したもの

算術演算子

算術演算子はその名の通り、四則演算を行うための演算子になります。

基本的には算数で習ったものと同じ使い方になります。

単項演算子

以下の算術演算子は単項演算子の形をとります。「<演算子> <値>

これらは値に対して単純に数値の正負の指定するものになります。

  • +:+符号。数を正の数として明記する。
  • -:-符号。数を負の数として明記する。
単項演算子の実行結果の画像

上のサンプルコード内の変数の値を表示して見たもの

インクリメントとデクリメント

プログラミング特有の演算子としてインクリメントとデクリメントという操作があります。これらは対象の値の数を+1、-1する演算子になり、それらを省略した書き方になります。

  • ++:インクリメント(increment)。対象の値の数を+1する。
  • --:デクリメント(decrement)。対象の値の数を-1とする。

また、これらの演算子には前置と後置の2通りの書き方があります。

  • 前置:値の前に書く書き方。「++ <値>」、「-- <値>」。他の演算が行われる前に値が変更される。
  • 後置:値の後に書く書き方。「<値> ++」、「<値> --」。他の演算が行われた後に値が変更される。

インクリメントはまだ解説していませんがループ処理などでよく利用されます。

インクリメントの実行結果の画像

上のサンプルコードの変数の値を表示したもの

2項演算子

以下の算術演算子は2項演算子の形をとります。「<左辺値> <演算子> <右辺値>

専門用語だと難しく感じますが、これらは算数の四則演算と同じになりますので安心してください。

  • +:足し算。
  • -:引き算。
  • *:掛け算。XはアルファベットのXと被るため、*(アスタリスク)が使われています。
  • /:割り算。
  • %:あまり算。割ったものの余りが演算結果として使われます。

また、演算子の後に=がつくものも用意されています。こちらは代入演算子と組み合わさったものとなり、左辺値と右辺値を演算した結果を左辺値に代入するものになります。

  • +=:足し算。
  • -=:引き算。
  • *=:掛け算。Xではなく*(アスタリスク)が使われています。
  • /=:割り算。
  • %=:あまり算。割ったものの余りが演算結果として使われます。
四則演算の実行結果の画像

上のサンプルコードの変数の値を表示したもの。(代入演算子のものは省いています)

使い方はとても簡単です。

しかし、以下の問題が発生するとバグの原因になるので注意してください。

  • 値の桁あふれ
  • 0除算
  • 整数型と浮動小数点型を組み合わせた計算

計算結果がおかしい場合は上記を疑ってみてください。それぞれ説明します。

値の桁あふれ(オーバーフロー)について

値の桁あふれ(オーバーフロー)とは計算の結果、使用している型の値の範囲を超えてしまった時に発生するプログラミング特有の計算に関する問題になります。

特に整数型において発生しやすいです。

以前の記事で型について説明した時、数値には使用する型によって値の範囲が決められていると説明しました。
値の桁あふれはこのことが原因で発生する問題で、注意しないと正しい計算結果が得られなかったり、思わぬバグの原因となります。

桁あふれが発生した時は、C#側で自動的に使用している型の値の範囲に収まるように数値を変更します。

また、整数型の時に桁あふれが発生したことを知らせてほしい場合はcheckedキーワードとuncheckedキーワードというC#の機能を使用してください。
これらのキーワードを使用することで、System.OverflowExceptionという例外が発生し、桁あふれに対する処理をプログラミングすることができます。

例外処理に関しては講座の別記事で扱います。簡単に言うと、予想外な処理が行われた時にそれを知らせるためのものになります。

浮動小数点型で桁あふれが発生した場合は例外は発生しませんその代わりにfloat.Infinity など不明な値と表現されます。この値を含んだ計算は全てfloat.Infinityなどになり、意味のない計算になってしまうので注意してください。

浮動小数点型の意味のない値の一覧

  • Infinity:無限大を表す。 float.IsInfinity()メソッドなどで判定できる。
  • Nan:値ではないことを表す。float.IsNan()メソッドなどで判定できる。

※以下で使われる例外についてはまだ解説していません。

0除算について

C#では整数型の計算の中で0除算が発生した時は System.DivideByZeroException という例外が発生します。

浮動小数点型の場合は、例外が発生しませんが、上で説明した不明な値を返します。

整数型と浮動小数点を組み合わせた計算の時の注意点

値を表現する型には整数型と浮動小数点型と異なるものがあると以前説明しましたが、これらを組み合わせて計算する時、型変換時に小数部分が切り捨てられ、その結果意図した計算結果とは異なるものになってしまうことがあります。

一般的に整数型から浮動小数点型へ変換した時は整数型の値そのままが実数に変換されます。

が、浮動小数点型から整数型に変換した時は、小数点以下の値は切り捨てられて整数型に変換されます。

そのような変換を望まない場合は全ての計算を浮動小数点型で行うか、四捨五入を行う処理を挟むか、C#の標準ライブラリであるSystem.Math.Floor()System.Math.Ceiling()などのメソッドを利用してください。

比較演算子

比較演算子は二つの値の大小を判定したり、同じ値かどうかを比較するための演算子になります。

比較演算子は2項演算子の形をとります。「<左辺値> <演算子> <右辺値>

比較演算子の演算結果はbool型になり、演算子の内容と同じならtrue、異なるならfalseが返されます。

数学との違いとして、C#では「0 <= a <= 100」というようには一度に3つ以上の値を比較することはできません。

0 <= a && a <= 100」と論理演算子を使用して、必ず2つずつ比較するようにしてください。(プログラミング言語によってはできるものも存在しています。)

  • ==:同じ値か?
  • !=:異なる値か?
  • <:左辺値の方が右辺値より小さいか?
  • >:左辺値の方が右辺値より大きいか?
  • <=:左辺値の方が右辺値より小さい、もしくは同じか?
  • >=:左辺値の方が右辺値より大きい、もしくは同じか?
比較演算子の実行結果の画像

上のサンプルコードの変数の値を表示したもの。コンパイルエラーになるものは省いています。

比較演算子には次の使用上の注意点がありますので、そちらについても簡単に説明していきます。

浮動小数点型の同値判定(==, !==)

実は浮動小数点型の同値判定は一般的にはあまり意味のない判定になります。

なぜなら浮動小数点型の計算では必ず誤差が生じるため、大体似通った値は取ることは保証できるのですが完全に一致することは滅多にありません(もちろん、全く同じ計算を全て同じ順序で行った時は同じ値になります。)

そのため浮動小数点型では有効桁数という計算中でこの桁までなら誤差を含まない範囲を設け、その桁の範囲までが一致しているなら同じ値だと判定することが一般的です。

有効桁数は作っているアプリによって決めてください。float型だと大体小数点2桁ぐらいが信頼できる値になりますが、それも計算対象によってまちまちです。

実際のアプリ開発では有効桁数の同値判定処理はメソッドとしてまとめると便利でしょう。

参照型の同値判定

参照型に==演算子を使用すると、両方とも同じデータを参照している時のみ同じ値だと判定します。

これは、参照型の中身が

  • どのデータを指し示しているか(アドレス)
  • 指し示しているデータ本体

の二つに分かれているためです。

参照型が指し示しているデータの内容までも一致しているかどうかを判定するためには、System.Object.Equals()メソッドを再定義(オーバーライド、override)して、こちらから同値判定処理を書く必要があります。

メソッドの再定義(オーバーライド)はC#のクラスの継承の機能の一つになりますので、詳しくは別の章で解説します。

UnityC# クラスの継承・抽象メソッドとオーバライド is, as, null, this, baseの使い方も解説
今回の記事ではクラスの継承についてみていきます。 Unityではコンポーネント自体がUnityEngine.MoneBehaviourを継承したものなので実は既に使用している機能になります。 さらにUnityEngine.MonoBehav...

論理演算子

論理演算子はbool型の値に対する演算子になり、その計算結果はbool型になります。(bool型はtruefalseの2種類のどちらかを取る値になります。)

論理演算子は単項演算子の形(「<演算子> <値>」)をとるものと2項演算子の形(「<左辺値> <演算子> <右辺値>」)をとるものがあります。

論理演算子はbool型の値を変更したり、複数のbool型の値を組み合わせて新しいbool型を作る時に使われるため、一般的に条件文の中で使われます。

単行演算子の形を取る論理演算子

  • !:演算対象を反転する。trueならfalseに、falseならtrueになる。

2項演算子の形をとる論理演算子

  • &&&:論理積。左辺値と右辺値の両方がtrueならtrueを、そうでないならfalseを返す。
  • |||:論理和。左辺値と右辺値の両方または片方がtrueならtrueを、両方ともfalseならfalseを返す。
  • ^:排他的論理和。左辺値と右辺値が異なる時はtrue、両方とも同じ値の時はfalseを返す。

&|^はビット演算子でも使用されています。

論理演算子の実行結果の画像

上のサンプルコードの変数の値を表示したもの。

ビット演算子 (少々上級者向け)

ビット演算子はビット演算という整数型に対する演算子になり、特にuintulongなどの符号無し整数型に対して使われます。

ビット演算子を用いた計算結果は先にあげた型(uintulong)だとその型に、それ以外の整数型だと基本的にint型になります。

ビット演算子には単項演算子の形(「<演算子> <値>」)をとるものと2項演算子の形(「<左辺値> <演算子> <右辺値>」)をとるものがあります。

また、ビット演算は整数型の値をコンピュータ寄りに解釈した時の演算になり、その演算はコンピュータの命令そのままを表すことが多い、低レベルな演算になります。

コンピュータでは全ての値を0と1の表す2進数として表現されています。そのためコンピュータ寄りの演算であるビット演算では整数型の値を2進数16進数で表現されることが多いです。(2進数と16進数については下の方で補足しています。)

ビット演算はフラグ処理アプリの実行速度を上げるためのコードの最適化にも使われます。

ただし、コードの最適化に関しましては現在ではコンパイラーによって行われることが多いため、その目的ではあまり使うことはお勧めしません。1900年代の古いコードを読むことがあった時、その中で使われているのを見ることがあるかもしれません。

また、ビット演算でも桁あふれが発生しますのでこちらでもcheckedキーワードを使用できます。

2進数と16真数について補足

以前の記事で解説しましたが、簡単な補足として、2進数は0と1だけで、16進数は0~9,A-Fの16個の文字で数値を表す書き方になります。

コード上での書き方は以下のものになります。

2進数:数値を0b0Bから始じめ、0と1だけで表現する。_を挟むことができる。例: 0b00110B1100_1010

16進数:数値を0x0Xから始め、0-9a-f(またはA-F)だけで表現する。例:0x19af0XFFFF9a4c

単行演算子の形を取る論理演算子

  • ~:全てのビットを反転する。0b0101なら0b1010に、b1100なら0b0011になる。

2項演算子の形をとる論理演算子

  • &&=:論理積。全ての同じ桁の値を比べ、両方の桁が1ならその桁を1に、そうではないなら0にする。
  • ||=:論理和。全ての同じ桁の値を比べ、片方の桁に1を含んでいたらその桁を1に、そうではないなら0にする。
  • ^^=:排他的論理和。全ての同じ桁の値を比べ、両方の桁の値が異なるならその桁を1に、そうではないなら0にする。
  • <<<<=:左シフト演算。ビットを右辺値の数分、左にずらす* (2^n)と同じ意味合いになる。
  • >>>>=:右シフト演算。ビットを右辺値の数分、右にずらす/ (2^n)と同じ意味合いになる。

&|^は論理演算子でも使用されています。

<<>>はシフト演算と呼ばれるものです。

シフト演算は値の中の桁をずらす操作になりますので、ずらした結果元々の値にあった桁が消えたり、新しい桁が生じることもあります。この際他の演算との整合性を保つため、新しく生じた桁には左シフトなら0が、右シフトなら1が生じます。

ビット演算子の実行結果の画像

上のサンプルコードの変数の値を表示したもの。2進数ではなく16進数表記で出力しています。

演算子の優先順位

ここまで演算子について一つ一つ見てきました。ですが、実際のプログラミングでは色々な演算子を組み合わせて使用することが普通です。

コンピュータでは一度に複数の演算を行うことは基本的(※)にできません。そのため、一つの式の中にある演算子をどの順序で使用するかはコンパイラーによって決定されます。

その際、各演算子には優先順位というものが設定されており、優先順位が高い方から計算されます。優先順位が同じものが続く場合はコンパイラーによって自動的に決定されます。

もし、先に演算したいものがある場合はそれらを()で括ってください。そうすることで括弧の中の演算が先に計算されます。

※コンピュータの中には複数の演算を同時行えるように設計されたものも存在しますが、スマートフォンなど市販されているコンピュータはできないものが大半です。

演算子の優先順位の一覧

  1. ++--!~
  2. */%
  3. +-
  4. <<>>
  5. <><=>=
  6. ==!=
  7. &
  8. ^
  9. |
  10. &&
  11. ||
  12. =、その他の代入を含める演算子(+=<<=など)

なお、ここであげた演算子以外にも演算子があります。それらにも優先順位があります。

が、自然に使うことができるように優先順位が決定されているので、あまり意識せずにプログラミングしていけるでしょう。

【実践】実際にそれぞれの演算子をUnityで使ってみよう

ここまでで、色々な演算子、およびその優先順位について見てきました。

一度に覚える必要はありませんが、スクリプトの内容を読んで「この部分は演算子を使っている」となんとなくわかるようになればOKです。

それではちょっとした力試しで下のコードから演算子を使っている部分を見つけてみましょう!

サンプルコード自体には深い意味はないので、軽くコードを読む練習にでも使ってください。

既に書かれたコードが読めるようになることはとても重要なプログラマーのスキルになるので頑張って読んでみてください!

色々な演算子を使ってみた時の動画

上のサンプルコードを実行した時の動画。Colorは灰色でValueは0.1で実行している。色が灰色ではなく緑に変化して微妙に上にも移動している。

サンプルコードでは次の部分で演算子を使用しています。(厳密にいうとまだ他のものもありますがここでは無視してください。)

  • メンバ変数の初期化部分
  • Start()メソッドの中全般
  • Update()メソッドの中全般

かなり大雑把に挙げましたが、演算子はプログラミングする上で本当によく使われていることを実感していただければOKです。

全て見つけられなくても何も問題はありません。

一回で全部覚えるのはきついしその必要もありません。徐々に慣れていきましょう。

ここで立ち止まらずに次の記事へ進んでいきましょう!

まとめ

今回の記事では演算子についてみてきました。スクリプトの中身は基本的には変数演算子、およびそれらを組み合わせてできたからできています。

ここで紹介した演算子以外にもソースコードの中にはまだたくさんの演算子がありますので、それらについても今後説明していきます。

また、いくつかの演算子はその処理内容を変更することができます。このことをC#では演算子のオーバーロードと呼んでいます。基本的にこちらが定義したクラスに対して使われることが多いです(以下の記事で詳しく解説)。

Unity C#のメソッド(関数)の使い方
今回の記事ではメソッド(関数)についてみていきます。 以前の記事でもメソッド自体を既に使っています。今回の記事を読むことで色々な種類のメソッドを作ることができますので、是非呼んでみてください。 前回の記事: メソッド(関数)とは メソッドと...

この記事の内容をおさらいすると次のようになります。

  • 演算子を使うことで色々な処理を行うことができる。
  • 代入演算子は変数に値を入れる演算のこと。
  • 算術演算子は足し算、引き算、掛け算、割り算、余り算のこと。
  • 比較演算子は値の大小や同じものかを判定するためのもの。
  • 論理演算子はbool型に対する演算で分岐処理でよく使われる。
  • ビット演算子はビット演算を行うための演算子のこと。
  • 演算子には優先順位が存在し、高いものから順に実行され、括弧を使うとその中のものが先に演算される。
  • 演算子の中にはこちらから処理内容を変更することができるものがある。

それでは、次の記事に行ってみましょう。

Unity C#の条件分岐の使い方 if文・switch文
今回の記事では制御文について解説していきます。 制御文にはいくつか分類があるのですが、ここでは条件分岐と呼ばれるif文とswitch文について見ていきます。 前回の記事: 制御文と条件分岐について 制御文とはプログラムの処理を実行するかしな...

初心者向けUnityC#入門講座に戻る>>



Unity入門の森オリジナル本格ゲーム制作講座はこちら
11種類の本格ゲームの全ソースコード公開・画像&動画による解説付き

コメント

タイトルとURLをコピーしました