UnityEngineのシミュレーションで学習
学習用シーン
次のような、3DプロジェクトにCubeを1つ配置したシーンで考えましょう
Hierarchy
シーンの管理のために使われます
シーンに初期状態で配置するゲームオブジェクトのリストになります
public class Scene
{
public string name { get; set; }
List<GameObject> gameObjects;
}
このコードは、C#で作られた「Scene」という名前のクラスを定義しています。
このクラスには、2つのフィールドがあります。
1つ目は、名前を表す「name」というプロパティです。このプロパティは、外部から読み取りや書き込みが可能であり、クラス内部でも使用されることがあります。
2つ目は、ゲームオブジェクトを格納するための「gameObjects」というList<T>型のフィールドです。このフィールドは、Sceneクラス内部で使用されるため、publicなアクセス修飾子は付けられていません。
このコードが定義されている場所が、名前空間(namespace)やその他のクラス定義があるファイルに依存しますが、一般的にはゲーム開発などのコンピュータグラフィックス分野において、シーン管理やオブジェクト管理などの用途で使用されます
Inspector
Cubeのインスペクターを個別にみていきましょう
Cubeが所有しているコンポーネントのリストが宣言されます
1つ1つのコンポーネントを継承しているインスタンスが代入されます
public class GameObject
{
List<Component> components;
}
このコードは、GameObject
という名前のクラスを定義しています。このクラスには、List<Component>
型のcomponents
というフィールドが含まれています。
List
は、複数のオブジェクトを保持するためのデータ構造であり、Component
は、GameObject
の構成要素を表すための基本クラスです。つまり、GameObject
には複数のComponent
を持つことができます。
List<Component>
は、ジェネリックスと呼ばれる機能を使用しています。ジェネリックスを使用することで、List
クラスは、指定された型のオブジェクトを保持できるようになります。ここでは、Component
型のオブジェクトを保持するために使用されています。
Transformコンポーネント
Cubeのインスペクター
サンプルでは、Positionプロパティのみピックアップしています
public class Transform : Component
{
public Vector3 position { get; set; }
}
このコードは、Unityエンジンで使用されるスクリプトの一部です。Transformクラスは、Unityオブジェクトの位置、回転、スケール情報を表すために使用されます。
このTransformクラスは、Componentクラスを継承しており、positionという名前のVector3型のプロパティを持っています。プロパティは、外部からアクセス可能であり、値を取得および設定することができます。したがって、他のスクリプトからTransform.positionにアクセスして、オブジェクトの位置を取得または変更できます。
なお、Vector3はUnityエンジンにおいて、3次元のベクトルを表すために使用される型です。Vector3型の変数は、x、y、およびzの3つの浮動小数点数値を持ちます。したがって、Transform.positionは、オブジェクトの3次元空間上での位置を表します
public struct Vector3
{
public float x;
public float y;
public float z;
public Vector3(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
このコードは、3次元ベクトルを表すための構造体を定義しています。構造体は、値型の一種であり、メモリ効率がよく、単純なデータ構造を表すのに適しています。
この構造体は、x、y、zの3つのfloat型のフィールドを持ちます。これらのフィールドは、Vector3構造体のインスタンスが作成されたときに初期化されます。
また、この構造体には、x、y、zの値を引数として受け取り、それらの値をフィールドに設定するパブリックなコンストラクタがあります。このコンストラクタは、Vector3構造体のインスタンスを作成するときに使用されます。
このように、Vector3構造体は、3つのfloat型の値をまとめて扱うための単純なデータ構造を提供します。これは、3Dグラフィックスや物理シミュレーションなどの分野でよく使われます。
BoxColliderコンポーネント
Cubeのインスペクター
サンプルでは、Centerプロパティのみピックアップしています
public class BoxCollider : Component
{
public Vector3 center { get; set; }
}
このコードは、BoxColliderというクラスを定義しています。
BoxColliderはComponentというクラスを継承しており、BoxColliderのインスタンスはGameObjectにアタッチされ、物理的な衝突判定を実現するための情報を保持するコンポーネントです。
BoxColliderクラスには、centerというpublicなVector3型のプロパティが定義されています。このプロパティは、BoxColliderが設定されたGameObjectの中心座標を表します。
また、centerプロパティはgetとsetメソッドが定義されているため、外部から値の取得と設定が可能です。
GetComponent<T>メソッドについて
public class GameObject
{
private readonly List<Component> components = new List<Component>();
public T? GetComponent<T>() where T : Component
{
return components.FirstOrDefault(comp => comp.GetType() == typeof(T)) as T;
}
}
このコードは、ゲームオブジェクトのコンポーネントを管理するためのクラス GameObject
を定義しています。このクラスは、ジェネリックメソッド GetComponent<T>
を公開し、指定された型 T
のコンポーネントを返します。
GetComponent<T>
メソッドは、where T : Component
という制約付きジェネリックメソッドであり、T
型が Component
クラスを継承していることが要件となっています。メソッドの戻り値は、T
型のnullableなオブジェクトで、components
フィールドに格納されているコンポーネントリストから最初に見つかった型が T
であるコンポーネントを取得します。
このコードでは、components
フィールドは List<Component>
型のリストであり、ゲームオブジェクトにアタッチされているすべてのコンポーネントが格納されます。FirstOrDefault
メソッドは、components
リストの最初に見つかった要素を取得します。comp => comp.GetType() == typeof(T)
は、ラムダ式で、comp
を引数として取り、comp
の型が T
であるかどうかをチェックします。最後に、as T
を使用して、取得したオブジェクトを T
型にキャストします。見つからなかった場合、GetComponent<T>
メソッドは null
を返します。
このコードは、Unityなどのゲームエンジンでよく見られる、コンポーネントベースのアーキテクチャにおいて、オブジェクトのコンポーネントを管理するために使用される一般的な手法です。
public class Component
{
public GameObject? gameObject;
public Transform transform
{
get
{
return GetComponent<Transform>();
}
}
public T? GetComponent<T>() where T : Component
{
return gameObject.GetComponent<T>();
}
}
このコードは、Unityエンジンで使われる Component
クラスの定義を示しています。
Component
クラスは、Unityのオブジェクトにアタッチされるすべてのコンポーネントのベースクラスであり、gameObject
と transform
の2つの公開プロパティを持っています。
gameObject
は、このコンポーネントがアタッチされているゲームオブジェクトへの参照を持ちます。gameObject
プロパティは GameObject
型のNullableなプロパティで、Nullableにすることでアタッチされているゲームオブジェクトがない場合に null を返すことができます。
transform
プロパティは、このコンポーネントがアタッチされているゲームオブジェクトのTransformコンポーネントを返します。transform
プロパティは、getアクセサでGetComponent<Transform>()メソッドを呼び出し、その結果を返します。
GetComponent<T>()
メソッドは、指定された型Tに一致するコンポーネントを返します。これは、このコンポーネントがアタッチされているゲームオブジェクトから GetComponent<T>()
メソッドを呼び出すことによって実現されます。ここでは、ジェネリック制約 where T : Component
を使用しているため、Tは Component
クラスかそのサブクラスである必要があります。また、GetComponent<T>()
メソッドは、T型のコンポーネントが見つからない場合はnullを返します。ここでも、ジェネリック型パラメータTはNullableとして宣言されているため、nullを返すことができます。
全コード
このコードは、UnityのGameObjectとTransform、Rigidbodyなどの概念を模倣して、C#のコードで表現しています。以下は、各クラスとその役割についての説明です。
- GameObject:Unityのゲームオブジェクトに相当するクラスで、コンポーネントを追加したり、ゲームオブジェクト自体の状態を管理します。
- Transform:UnityのTransformコンポーネントに相当するクラスで、ゲームオブジェクトの位置、回転、スケールなどを管理します。
- Rigidbody:UnityのRigidbodyコンポーネントに相当するクラスで、ゲームオブジェクトの物理的な動きを管理します。
- BoxCollider : ゲームオブジェクトに物理的な境界を与えるためのコンポーネントの1つです。Box Colliderは、直方体の形状を持ち、そのオブジェクトの形状を定義するために使用されます。
- MonoBehaviour:UnityのMonoBehaviourクラスに相当するクラスで、Unityのライフサイクルメソッド(Start、Update、Awakeなど)を実装するための基底クラスです。
このコードでは、MainメソッドでGameObjectを作成し、Transform、Rigidbody、そしてManagerコンポーネントを追加しています。Managerコンポーネントは、MonoBehaviourを継承しており、StartメソッドでRigidbodyの使用重力を有効にし、Transformの位置を変更し、Debug.Logを使用して位置を出力しています。Debugクラスは、単純なデバッグログをコンソールに出力するために使用されます。
このコードは、Unityの開発における基本的な概念を理解するのに役立つでしょう。
using UnityEngine;
internal class Program
{
private static void Main()
{
var car1 = new GameObject();
car1.AddComponent<Transform>();
car1.AddComponent<Rigidbody>();
car1.AddComponent<Manager>().Start();
}
}
public class Scene
{
public string? name { get; set; }
List<GameObject>? gameObjects;
}
public class Manager : MonoBehaviour
{
private Rigidbody? rigidBody;
public void Start()
{
rigidBody = GetComponent<Rigidbody>();
rigidBody.useGravity = true;
transform.position = new Vector3(1, 2, 3);
transform.Translate(new Vector3(10, 0, 0));
Debug.Log($"PosX = {transform.position.x}");
gameObject.AddComponent<BoxCollider>();
BoxCollider boxCollider = GetComponent<BoxCollider>();
boxCollider.center = new Vector3(10, 20, 30);
Debug.Log($"BoxCollicerCenterX = {boxCollider.center.x}");
}
}
public class Debug
{
public static void Log(object value)
{
Console.WriteLine(value);
}
}
namespace UnityEngine
{
public class Debug
{
public static void Log(object value)
{
Console.WriteLine(value);
}
}
public class GameObject
{
private readonly List<Component> components = new List<Component>();
public T? GetComponent<T>() where T : Component
{
return components.FirstOrDefault(comp => comp.GetType() == typeof(T)) as T;
}
public T AddComponent<T>() where T : Component, new()
{
var component = new T { gameObject = this };
components.Add(component);
return component;
}
}
public class Component
{
public GameObject? gameObject;
public Transform transform
{
get
{
return GetComponent<Transform>()!;
}
}
public T? GetComponent<T>() where T : Component
{
return gameObject!.GetComponent<T>();
}
}
public class MonoBehaviour : Component
{
}
public class Transform : Component
{
public Vector3 position { get; set; }
public void Translate(Vector3 translation)
{
position += translation;
}
}
public struct Vector3
{
public float x;
public float y;
public float z;
public Vector3(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
public static Vector3 operator +(Vector3 a, Vector3 b)
{
return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
}
}
public class BoxCollider : Component
{
public Vector3 center { get; set; }
}
public class Rigidbody : Component
{
public bool useGravity { get; set; }
}
}
機能説明
演算子のオーバーロード
public static Vector3 operator +(Vector3 a, Vector3 b)
{
return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
}
このコードは、3次元ベクトル(Vector3)の加算演算子(+)のオーバーロード実装を示しています。
Vector3型の引数aとbを取り、それらのx、y、zの成分を足し合わせた新しいVector3を作成しています。具体的には、x成分はa.xとb.xを加算し、y成分はa.yとb.yを加算し、z成分はa.zとb.zを加算した新しいVector3を返します。
このようにオーバーロード演算子を実装することで、2つのVector3を直感的に足し合わせることができます。例えば、以下のように記述することができます。
Vector3 a = new Vector3(1, 2, 3);
Vector3 b = new Vector3(4, 5, 6);
Vector3 c = a + b; // c = (5, 7, 9)
クラス図
このコードは、Unity game engine におけるゲームオブジェクトの作成と操作を行うためのサンプルコードです。以下に、各部分の説明を示します。
最初の部分は、Unity Engine の名前空間である「UnityEngine」を使用しています。そして、Program クラスの Main メソッドでは、新しい GameObject インスタンスを作成し、その上に Transform、Rigidbody、Manager コンポーネントを追加しています。
Scene クラスは、シーンの名前とそのシーン内に存在するすべての GameObject を格納するために使用されるクラスです。
Manager クラスは、MonoBehaviour クラスを継承しています。MonoBehaviour は、Unity game engine 内でスクリプトを動作させるための基底クラスであり、ゲームオブジェクト上で実行されます。Manager クラスでは、Start メソッドが定義されており、ゲームオブジェクトの Rigidbody コンポーネントの使用重力フラグを有効にしたり、Transform コンポーネントの位置を変更するなどの動作を行います。また、BoxCollider コンポーネントを追加し、その中心座標を変更するなどの動作も行っています。
Debug クラスは、単純なログ出力を行う静的メソッド Log を定義しています。
UnityEngine 名前空間には、GameObject、Component、MonoBehaviour、Transform、BoxCollider、Rigidbody の各クラスが定義されており、ゲームオブジェクトの作成と操作を行うための機能を提供しています。GameObject クラスは、コンポーネントを持つ Unity ゲームオブジェクトを表します。Component クラスは、GameObject 上のコンポーネントを表します。Transform クラスは、GameObject の座標、回転、拡大縮小を制御するコンポーネントを表します。BoxCollider クラスは、物理エンジンとの衝突判定のための矩形のコリジョン形状を定義します。Rigidbody クラスは、ゲームオブジェクトに物理挙動を付加するコンポーネントです。そして、MonoBehaviour クラスは、ゲームオブジェクト上でスクリプトを実行するための基底クラスです。
実行結果
PosX = 11
BoxCollicerCenterX = 10
おまけ
ゲームオブジェクトを見つける(GameObject.Findメソッド)を追加しています
このコードはUnityのシーンを模倣するための簡単なコード例です。このコードでは、GameObject、Transform、Rigidbody、BoxCollider、そして自作のManagerクラスが定義されています。
まず、ProgramクラスのMainメソッドで、新しいSceneオブジェクトを作成し、名前を"Test"に設定しています。次に、2つの車両を表すGameObjectを作成し、それぞれにTransformとRigidbodyコンポーネントを追加します。car2には名前を設定しています。最後に、car1にManagerコンポーネントを追加しています。
ManagerクラスのStartメソッドでは、car1のRigidbodyコンポーネントを取得して、useGravityプロパティをtrueに設定しています。transformプロパティを使用して、car1の位置を変更し、Translateメソッドを使用して、さらに移動しています。Debugクラスを使用して、コンソールに現在の位置を表示しています。
また、car2にBoxColliderを追加し、centerプロパティを変更しています。GameObject.Findメソッドを使用して、名前が"car2″のGameObjectを検索しています。car2の位置を変更し、Translateメソッドを使用して、さらに移動しています。Debugクラスを使用して、コンソールに現在の位置を表示しています。
このコードはUnityの機能の一部を模倣していますが、実際のUnityプロジェクトとは異なることに注意してください。また、このコードはC#言語を使用しており、UnityのAPIとは異なることにも注意してください。
// この行は、UnityEngine名前空間を使用することを示しています。
// UnityEngineはUnityエンジンの核となるライブラリです。
using UnityEngine;
/// <summary>
/// unityエンジンの内部コントロールのイメージです
/// 実行前の初期画面のデザイン設計と考えましょう
/// </summary>
internal class Program
{
// メインメソッド
private static void Main()
{
// 新しいSceneオブジェクトを作成し、名前を"Test"に設定する
Scene scene = new Scene();
scene.name = "Test";
// 新しい空のGameObjectオブジェクトを2つ作成し、それぞれTransformコンポーネントとRigidbodyコンポーネントを追加する
var car1 = new GameObject();
car1.AddComponent<Transform>();
car1.AddComponent<Rigidbody>();
car1.name = "Car1";
var car2 = new GameObject();
car2.AddComponent<Transform>();
car2.AddComponent<Rigidbody>();
// 2つめのGameObjectオブジェクトの名前を"car2"に設定する
car2.name = "Car2";
// 作成した2つのGameObjectオブジェクトをSceneオブジェクトに追加する
scene.AddGameObject(car1);
scene.AddGameObject(car2);
// 最初のGameObjectオブジェクトにManagerコンポーネントを追加し、Startメソッドを呼び出す
car1.AddComponent<Manager>().Start();
}
}
/// <summary>
/// car1オブジェクトにアタッチするスクリプトのイメージです
/// Managerクラスを定義する。MonoBehaviourを継承する。
/// </summary>
public class Manager : MonoBehaviour
{
// Rigidbody型のprivate変数rigidBodyを宣言する。
private Rigidbody rigidBody;
// Startメソッドを定義する。
public void Start()
{
// 自分自身のGameObjectからRigidbodyコンポーネントを取得し、rigidBodyに代入する。
rigidBody = GetComponent<Rigidbody>();
// rigidBodyのuseGravityプロパティをtrueにする。
rigidBody.useGravity = true;
// 自分自身のGameObjectの位置をVector3(1, 2, 3)に設定する。
transform.position = new Vector3(1, 2, 3);
// 自分自身のGameObjectの位置をVector3(10, 0, 0)だけ移動する。
transform.Translate(new Vector3(10, 0, 0));
// ログを出力する。transform.positionのx座標を表示する。
Debug.Log($"PosX = {transform.position.x}");
// 自分自身のGameObjectにBoxColliderコンポーネントを追加する。
gameObject.AddComponent<BoxCollider>();
// 自分自身のGameObjectからBoxColliderコンポーネントを取得し、boxColliderに代入する。
BoxCollider boxCollider = GetComponent<BoxCollider>();
// boxColliderのcenterをVector3(10, 20, 30)に設定する。
boxCollider.center = new Vector3(10, 20, 30);
// ログを出力する。boxColliderのcenterのx座標を表示する。
Debug.Log($"BoxCollicerCenterX = {boxCollider.center.x}");
// "car2"という名前のGameObjectを検索し、car2に代入する。
GameObject car2 = GameObject.Find("Car2");
// car2の名前をログに出力する。
Debug.Log(car2.name);
// car2の位置をVector3(20, 21, 22)に設定する。
car2.transform.position = new Vector3(20, 21, 22);
// car2の位置をVector3(0, 2, 3)だけ移動する。
car2.transform.Translate(new Vector3(0, 2, 3));
// ログを出力する。car2の位置のz座標を表示する。
Debug.Log($"car2Posz = {car2.transform.position.z}");
}
}
// このコードはUnityのエンジンに含まれるUnityEngine名前空間を定義するためのものです。
// 名前空間は、関連するクラス、構造体、列挙型などのグループ化されたコードの集まりを提供します。
namespace UnityEngine
{
// Debugクラス:ログ出力を行う
public class Debug
{
// Logメソッド:渡されたオブジェクトをコンソールに出力する
public static void Log(object value)
{
Console.WriteLine(value);
}
}
// Sceneクラス:シーンを表す
public class Scene
{
// シーンの名前
public string name { get; set; }
// シーン内に存在するGameObjectのリスト
public static List<GameObject> gameObjects = new List<GameObject>();
// GameObjectをシーンに追加するメソッド
public void AddGameObject(GameObject gameObject)
{
gameObjects.Add(gameObject);
}
}
// GameObjectクラス:オブジェクトを表す
public class GameObject
{
// オブジェクトの名前
public string name { get; set; }
// オブジェクトのTransformコンポーネント
public Transform transform
{
get
{
return GetComponent<Transform>();
}
}
// オブジェクトが持つコンポーネントのリスト
private readonly List<Component> components = new List<Component>();
// オブジェクトが持つ、指定された型のコンポーネントを取得するメソッド
public T GetComponent<T>() where T : Component
{
return components.FirstOrDefault(comp => comp.GetType() == typeof(T)) as T;
}
// オブジェクトに新しいコンポーネントを追加するメソッド
public T AddComponent<T>() where T : Component, new()
{
var component = new T { gameObject = this };
components.Add(component);
return component;
}
// オブジェクト名が一致する最初のGameObjectを返す静的メソッド
public static GameObject Find(string name)
{
return Scene.gameObjects.FirstOrDefault(gameObject => gameObject.name == name);
}
}
// コンポーネントの基本クラス
public class Component
{
// ゲームオブジェクト
public GameObject gameObject;
// transformプロパティ
public Transform transform
{
get
{
return GetComponent<Transform>(); // ゲームオブジェクトからTransformコンポーネントを取得して返す
}
}
// 指定された型のコンポーネントをゲームオブジェクトから取得する
public T GetComponent<T>() where T : Component
{
return gameObject.GetComponent<T>();
}
}
// MonoBehaviourクラス。Componentクラスを継承する
public class MonoBehaviour : Component
{
}
// Transformクラス。Componentクラスを継承する
public class Transform : Component
{
// 座標
public Vector3 position { get; set; }
// 移動する
public void Translate(Vector3 translation)
{
position += translation;
}
}
// Vector3構造体を定義する
public struct Vector3
{
// x、y、zの値を保持するpublicフィールドを宣言する
public float x;
public float y;
public float z;
// Vector3構造体のインスタンスを作成するためのコンストラクタ
public Vector3(float x, float y, float z)
{
// コンストラクタの引数を各フィールドに代入する
this.x = x;
this.y = y;
this.z = z;
}
// Vector3型の加算演算子を定義する
public static Vector3 operator +(Vector3 a, Vector3 b)
{
// 2つのVector3インスタンスのx、y、zを加算したVector3インスタンスを返す
return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
}
}
// BoxColliderクラスを定義する
public class BoxCollider : Component
{
// BoxColliderの中心座標を保持するVector3型のプロパティ
public Vector3 center { get; set; }
}
// Rigidbodyクラスを定義する
public class Rigidbody : Component
{
// 重力の有無を表すbool型のプロパティ
public bool useGravity { get; set; }
}
}
実行結果
PosX = 11;
BoxCollicerCenterX = 10
car2
car2Posz = 25
クラス図
基本のシーン構成とCube1
Cube2
Manager.cs
/// <summary>
/// car1オブジェクトにアタッチするスクリプトのイメージです
/// Managerクラスを定義する。MonoBehaviourを継承する。
/// </summary>
public class Manager : MonoBehaviour
{
// Rigidbody型のprivate変数rigidBodyを宣言する。
private Rigidbody rigidBody;
// Startメソッドを定義する。
public void Start()
{
// 自分自身のGameObjectからRigidbodyコンポーネントを取得し、rigidBodyに代入する。
rigidBody = GetComponent<Rigidbody>();
// rigidBodyのuseGravityプロパティをtrueにする。
rigidBody.useGravity = true;
// 自分自身のGameObjectの位置をVector3(1, 2, 3)に設定する。
transform.position = new Vector3(1, 2, 3);
// 自分自身のGameObjectの位置をVector3(10, 0, 0)だけ移動する。
transform.Translate(new Vector3(10, 0, 0));
// ログを出力する。transform.positionのx座標を表示する。
Debug.Log($"PosX = {transform.position.x}");
// 自分自身のGameObjectにBoxColliderコンポーネントを追加する。
gameObject.AddComponent<BoxCollider>();
// 自分自身のGameObjectからBoxColliderコンポーネントを取得し、boxColliderに代入する。
BoxCollider boxCollider = GetComponent<BoxCollider>();
// boxColliderのcenterをVector3(10, 20, 30)に設定する。
boxCollider.center = new Vector3(10, 20, 30);
// ログを出力する。boxColliderのcenterのx座標を表示する。
Debug.Log($"BoxCollicerCenterX = {boxCollider.center.x}");
// "car2"という名前のGameObjectを検索し、car2に代入する。
GameObject car2 = GameObject.Find("Car2");
// car2の名前をログに出力する。
Debug.Log(car2.name);
// car2の位置をVector3(20, 21, 22)に設定する。
car2.transform.position = new Vector3(20, 21, 22);
// car2の位置をVector3(0, 2, 3)だけ移動する。
car2.transform.Translate(new Vector3(0, 2, 3));
// ログを出力する。car2の位置のz座標を表示する。
Debug.Log($"car2Posz = {car2.transform.position.z}");
}
}
実行結果
Cub1の位置(InspectorのTransformのPosition Yの値がどんどんマイナスに大きくなっていっているのがわかります(落下しています)
これは、RigidbodyのuseGravityプロパティをtrueにしたためです
Consoleの表示されるデバッグ情報にも注意を向けましょう
ディスカッション
コメント一覧
まだ、コメントがありません