このブログで使用しているUnityのVer
・Unity 2022.3.19f1
はじめに
こんちは!ゆっくりゲーム制作、えきふるです。
UnityでC#プログラムを書いていると絶対に扱うClass(クラス)。
これ、プログラミング独学だと何となく雰囲気で使っているけど、しっかり構造は理解していないって事ないでしょうか。私はそう。
プログラムなんて触れて来なかったから、ネットの独学でなおさら雰囲気で使ってたふる…
ということで、以前の記事で少しだけ触れているのですが、今回はClassだけに絞って掘り下げてみたいと思います。
C#におけるClass(クラス)とは?
Class(クラス)とは簡単に言うと「関連しているデータと処理をひとまとめにしたもの」です。
かつてのプログラムでは全て1つの塊でズラーっと書いてあったようですが、これだとどこに何が書いてあるかが非常に分かりづらい記述になってしまいます。
一方で、オブジェクト指向と言われるプログラム言語ではこのように関連の強い処理をプログラム毎にまとめる事で再利用や情報の整理がしやすい構造となっているようですね。
プログラムを扱いやすくするために生まれたものみたい
Classのプログラム構造
それではC#のプログラム構造を見ていきましょう。
基本的には下記のようになっています。
class クラス名
(
データメンバー
関数メンバー
)
上記で記載されている「データメンバー」とは
public データ型 変数名;
のようなクラス内で宣言される変数と
const データ型 定数名 = 初期値;
のような変化することのない定数を宣言する部分になります。
一方で、「関数メンバー」とはメソッド等を含む処理や動作機能を記述した部分となります。
データメンバーと関数メンバーをUnity C#でサンプルとして書いてみると
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
//データメンバー
public int a;
//関数メンバー
void Start()
{
a += 1;
}
}
こんなイメージになります。
基本的な事で意識しなかったりするけど、データメンバーと関数メンバーはカテゴリが違う事は理解しておこう!
TIPS:MonoBehaviour(モノビヘイビア)ってなに?
Unity内でC#スクリプトを生成すると勝手にクラス部分に
public class Sample : MonoBehaviour
と言うふうに「MonoBehaviour」というものが記述されていることに気づくと思います。
このMonoBehaviourとは何なのかというと、Unity側で用意されている基本クラスです。
この基本クラスではそもそもUnity内でゲームオブジェクトのコンポーネントにC#をアタッチ出来るようにする機能や、Start()やUpdate()といったゲーム制作用のメソッドが最初から使えるようになっている超便利なクラスです。
サンプルコードのようにclass名の横に「MonoBehaviour」と記載されることでこの「Sample」というclassに「MonoBehaviour」classで定義された内容を継承させて、基本クラスのメンバーが使えるようにしています。
試しに「test2」というMonoBehaviourの記述を消したスクリプトを用意してオブジェクトにアタッチするテストをしてみました。
MonoBehaviourの記述以外は最初に生成されたスクリプトそのままです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test2 //ここにあるはずのMonoBehaviourの記述が無い
{
void Start()
{
}
void Update()
{
}
}
このスクリプトをUnity上でオブジェクトにアタッチしようとすると下記のように「アタッチ出来ないよ」と注意されました。
よく知らなかったけど、「MonoBehaviour」って必要な記述だったのふるね・・・
Classの使い方
Unityでゲーム制作をしている人は当たり前のようにクラスに処理を記述し、C#プログラムファイルをコンポーネントにアタッチして使用していると思いますが、ここでClassの使い方をしっかり確認していきましょう。
Classはよく「設計図」という言われ方をします。
そこで例えとしてロボットを作る工場をイメージしてどんな使われ方なのか概念を確認してみましょう。
まず、ロボットを作るためにベースの設計図として、Classの中にそれぞれの必要な各パーツやそのパーツの動作の説明を記載します。名前、腕部、脚部、体躯部、頭パーツ、武器1、武器2、など。
この設計図をもとにロボット(インスタンスと言います)を作ります。
この時、各パーツのベース構造は一緒でもロボット毎にカスタマイズができます。
名前は当然自由に付けられますし、腕部を細い高起動型にしたり、脚部をキャタピラにしたり、武器をレーザー銃にしたり・・・・
さらに、組み立てる際には実際の工場のように
ロボットを組み立て、配置するスペースを確保し、仲間にどこに配置しているかわかるように看板を立て、組み立てていきます。
・・・何だかアーマードコアやメダロットみたいですね。
このようにClassを設計図として実際に組み立てて使用していきます。これをClassのインスタンス化と言います。
次の項目で実際にC#のインスタンス化の仕方を見ていこう!
インスタンス化
設計図は実態が無い(実際のオブジェクトが無い)ものなのでこの設計図をもとに実態を宣言してプログラムの中で使っていきます。(インスタンス化)
宣言の仕方は下記のように記述します。
クラス名 変数名(インスタンス名);
この宣言によって、この「変数名」のアドレスを確保します。
アドレスの確保とはどこにデータがあるかを示している状態で、先ほどの例えで言うと「看板」に当たります。
ただ、この時点では場所を示した看板を立てても、その場所には実態はまだありませんので、この状態で変数の中を見ても「null」が表示されます
それではこの看板で示した場所に設計図をもとに実態を作成します。(=これをインスタンス化と言います)
その記述の仕方は
変数名(インスタンス名) = new クラス名();
となります。
このnew演算子を使用した時にメモリの確保と同時に実態が作成されます。
メモリの確保とは先ほどの例えで言うと「組み立てスペースの確保」に当たります。
ロボットを組み立てた後に、さらに各項目をカスタマイズできます。カスタマイズの仕方は
変数名(インスタンス名).メンバー名
と記述し、各メンバーにアクセスして上書きします。
実際に具体的なスクリプトを見てみましょう。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Robot//インスタンスするための元のクラス(設計図)
{
public string namae = "";
public int arm = 2 ;
}
public class Instance : MonoBehaviour
{
void Start()
{
Robot robot01 ; //アドレス登録
robot01 = new Robot(); //メモリを確保してインスタンス作成
robot01.namae ="試作ロボ1号"; //設計図に沿ってカスタマイズ
robot01.arm = 5 ;
Debug.Log(robot01.namae);
Debug.Log(robot01.arm);
}
}
このスクリプトをUnity上のゲームオブジェクトオブジェクトにアタッチ、ゲームプレイしてデバッグログを確認してみます。
しっかりとデバッグログに「試作ロボ1号」と「5」の値が返ってきました。
ちなみに、
Robot robot01 ; //アドレス登録
robot01 = new Robot(); //メモリを確保してインスタンス作成
のところは、1つにまとめて
Robot robot01 = new Robot();
と言う書き方も可能です。
なお、インスタンス元となるクラスに関してはMonoBehaviourを継承させていません。
MonoBehaviourはUnity上の特殊なクラスでUnityエンジンの中でのみ機能する特殊なクラスなため、スクリプト内のnew演算子でインスタンス化ができません。
その為、そのクラスを継承させるとインスタンス化が正しく行われないのです。
インスタンスして使う事で同じパラメーター群で色んな敵キャラ作ったりするのに役立ちそうふるね〜!
TIPS:Unityエンジン側での自動インスタンス生成
ところで、Unityでゲーム制作をしている時、クラスのインスタンス化なんてしなくてもStartとかUpdateクラスに直接書き込めば動くじゃん、必要無くね?と思いませんでしたか?
私は思いました。
先ほど、MonoBehaviourはUnityエンジンの中でのみ機能する特殊なクラスだと説明しました。
実はこのMonoBehaviourクラスによって、スクリプトがゲームオブジェクトにアタッチされた際にUnity内でMonoBehaviourを継承したクラスがメモリを確保、インスタンス化されます。
そしてインスペクターを通じてメンバー変数にアクセスしてインスタンス化された変数の項目を書き換えているんです。
だからスクリプト内でnew演算子を使ったインスタンス化ができないんだ・・・
TIPS:nullって何?
クラス名 変数名(インスタンス名);
でインスタンスの変数を宣言しても、この時点では中身が「null」になっていると説明しました。
この「null」とは何でしょうか。
nullは「何も指していない状態」を表す値です。
アドレスの確保=看板を立てても、その看板の所にはまだ何も無い。
つまり何も参照されているオブジェクトが無い、と言う状態になります。
このnullにもメリットがあり、インスタンスしたクラスにnullを代入することでデータの初期化をしたり、
null状態かどうかで初期状態か値が入っているかなどのエラーチェック等にも使えます。
Static〜静的メンバーの使い方〜
インスタンス化され実体を持った変数達はそれぞれ独立した値(メンバー)を持ちます。
これらはインスタンスメンバーと呼ばれます。
一方、インスタンスに影響を受けずにClassにのみ属するメンバーがあります。
これらは静的メンバーと呼ばれ定数や全体で共有する設定値などのインスタンスからの影響が無く変化の無い値を扱うのに適しています。
静的メンバーの使い方は記述したいClass内で「static」キーワードをつけるだけです。
例として、先ほどのサンプルコードに静的メンバーを追加してみました。
public class Robot//インスタンスするための元の設計図
{
public string namae = "";
public int arm = 2 ;
public static string rider = "Hero";
}
riderと言う文字変数でHeroと言う名前を静的にしました。
どのロボットでも乗る主人公は変わらないよ、と言うイメージです。
それではインスタンス化したクラスからこの静的メンバーにアクセスしてみましょう。
アクセスの仕方は
クラス名.メンバー名
となります。この時、インスタンス名.メンバー名では無いことに注意してください。
静的メンバーはインスタンスに属さず、Classに属している為です。
それでは具体的なスクリプトで静的メンバーの呼び出しを確認してみましょう。
using System.Collections;
using System.Collections.Generic;
using JetBrains.Rider.Unity.Editor;
using UnityEngine;
public class Robot//インスタンスするための元の設計図
{
public string namae = "";
public int arm = 2 ;
public static string rider = "Hero"; //静的メンバーの作成
}
public class Instance : MonoBehaviour
{
void Start()
{
Robot robot01 = new Robot();
robot01.namae ="試作ロボ1号"; //設計図に沿ってカスタマイズ
robot01.arm = 5 ;
Debug.Log(robot01.namae);
Debug.Log(robot01.arm);
Debug.Log(Robot.rider);//ここで静的メンバーの呼び出し
}
}
このスクリプトを先ほどと同様にUnity上のオブジェクトにアタッチしてゲームプレイで確認します。
ちゃんとDebugログにHeroと表示されました!
このように静的メンバーは他クラスから直接呼び出すことができます。
これにてClassの使い方の基本を終わりにしますふる!
終わりに
今回はClassの概要、インスタンス化、静的メンバーの使い方などを確認していきました。
インスタンス化はUnityではオブジェクトにスクリプトをアタッチする事で自動で行われますが、
Unity上とは別に内部的なアイテム管理やステータス管理に使ったりするなど、システムによっては使う機会もあるかもしれません。
ClassはC#の基本でもありますので、今回の記事で少しでも理解が深まったら幸いです。
複雑な概念だけどゆっくり、しっかり理解していこー!
もし質問や感想があれば、コメントで教えて下さいね。
コメント貰えると元気も出ますので、どうぞお気軽にお願いしますふる!
※このブログは、UnityTechnologiesまたはその関連会社が後援または提携しているものではありません。「Unity」は、UnityTechnologiesまたはその関連会社の米国およびその他の国における商標または登録商標です。
コメント