unity3d
デザインパターン
サーチ…
モデルビューコントローラ(MVC)デザインパターン
モデルビューコントローラは、非常に一般的なデザインパターンであり、かなり長い間存在してきました。このパターンは、クラスを機能部品に分けることによってスパゲッティコードを減らすことに焦点を当てています。最近、私はUnityでこのデザインパターンを試していて、基本的な例を説明したいと思います。
MVCデザインは、Model、View、Controllerの3つのコア部分で構成されています。
モデル:モデルは、オブジェクトのデータ部分を表すクラスです。これはプレーヤー、目録、またはレベル全体である可能性があります。正しくプログラムされていれば、このスクリプトを使用してUnityの外で使用することができます。
モデルについていくつか注意してください。
- Monobehaviourから継承すべきではありません
- それは移植性のためのUnity特有のコードを含んではいけません
- Unity API呼び出しを避けているので、これはModelクラスの暗黙のコンバータのようなものを妨げる可能性があります(回避策が必要です)
Player.cs
using System;
public class Player
{
public delegate void PositionEvent(Vector3 position);
public event PositionEvent OnPositionChanged;
public Vector3 position
{
get
{
return _position;
}
set
{
if (_position != value) {
_position = value;
if (OnPositionChanged != null) {
OnPositionChanged(value);
}
}
}
}
private Vector3 _position;
}
Vector3.cs
データモデルで使用するカスタムVector3クラス。
using System;
public class 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;
}
}
ビュー:ビューは、モデルに関連付けられた表示部分を表すクラスです。これはMonobehaviourから派生するのに適したクラスです。これには、 OnCollisinEnter
、 Start
、 Update
などのUnity固有のAPIと直接対話するコードが含まれている必要があります。
- 一般的にMonobehaviourから継承します
- ユニティ固有のコードが含まれています
PlayerView.cs
using UnityEngine;
public class PlayerView : Monobehaviour
{
public void SetPosition(Vector3 position)
{
transform.position = position;
}
}
コントローラ:コントローラは、モデルとビューの両方をバインドするクラスです。コントローラは、モデルとビューの両方を同期させ、ドライブのやりとりを維持します。コントローラは、いずれかのパートナーからのイベントをリッスンし、それに応じて更新することができます。
- 同期状態でモデルとビューの両方をバインドする
- パートナー間の交流を促進できます
- コントローラはポータブルでも、そうでなくてもかまいません(Unityコードをここで使用する必要があります)
- コントローラを移植可能にしない場合は、エディタの検査に役立つMonobehaviourを使用することを検討してください
PlayerController.cs
using System;
public class PlayerController
{
public Player model { get; private set; }
public PlayerView view { get; private set; }
public PlayerController(Player model, PlayerView view)
{
this.model = model;
this.view = view;
this.model.OnPositionChanged += OnPositionChanged;
}
private void OnPositionChanged(Vector3 position)
{
// Sync
Vector3 pos = this.model.position;
// Unity call required here! (we lost portability)
this.view.SetPosition(new UnityEngine.Vector3(pos.x, pos.y, pos.z));
}
// Calling this will fire the OnPositionChanged event
private void SetPosition(Vector3 position)
{
this.model.position = position;
}
}
最終使用
主要な部分がすべて完成したので、3つの部分すべてを生成するファクトリを作成できます。
PlayerFactory.cs
using System;
public class PlayerFactory
{
public PlayerController controller { get; private set; }
public Player model { get; private set; }
public PlayerView view { get; private set; }
public void Load()
{
// Put the Player prefab inside the 'Resources' folder
// Make sure it has the 'PlayerView' Component attached
GameObject prefab = Resources.Load<GameObject>("Player");
GameObject instance = GameObject.Instantiate<GameObject>(prefab);
this.model = new Player();
this.view = instance.GetComponent<PlayerView>();
this.controller = new PlayerController(model, view);
}
}
そして最後に、マネージャーから工場に電話することができます...
Manager.cs
using UnityEngine;
public class Manager : Monobehaviour
{
[ContextMenu("Load Player")]
private void LoadPlayer()
{
new PlayerFactory().Load();
}
}
シーン内の空のGameObjectにManagerスクリプトを添付し、コンポーネントを右クリックして "Load Player"を選択します。
より複雑なロジックの場合は、抽象基本クラスとインタフェースを継承して、改良されたアーキテクチャを導入することができます。