29 Temmuz 2016 Cuma
28 Temmuz 2016 Perşembe
Observer Pattern in Unity3D
Observer Pattern Nedir?
Observer Pattern Object Oriented Programing içerisinde tanımlı design modellerinden biridir.
Kısaca bir nesnede olan değişikliklerden diğer nesnelerin haberdar olmasını sağlar.
3 bileşeni vardır:
Unity için bir örnek üzerinden anlatmaya devam edelim:
Diyelimli sahnemizde bir GameObject nesnesi var ve buna "boss" diyelim. Bir alan içerisinde bunun hareket ettiğini ve duvarlara temas ettiğinde yön değiştirdiğini faredelim. "boss" un sahip olduğu 4 tane de koruması "guard" ı temsil eden GameObjectler olduğunu düşünelim. Bu "guard"ların "boss"un çevresinde onu korumak için hareket ettiğini farz edelim. Bu durumda "boss" ObserverPattern içerisinde "Subject", "guar"lar ise yine ObserverPattern içerisinde "Subscriber" olarak tanımlarız.
ObserverPattern kullanmıyor olsaydık en basit yoldan bu senaryoyu gerçekleştirmek için "boss" için yarattığımız scrit içerisinde kaç tane guard varsa bunları tanımlamamız gerekirdi. Diyelim daha fazla guar olacak bunlarıda bir şekilde bu script e eklemek veya bir liste içerisinde tutmak gerekecekti.
ObserverPattern kullandığımız zaman ise "boss" ve "guard"lar birbirinden habersiz olacak ve guardlar Observer dan "boss" un hareketi ile ilgili bilgi isteyecek. "boss" ise Observer a hareketi ile ilgili bilgi gönderecek.
Şimdi yavaş yavaş Unity için Observer Pattern'ımızı kuralım.
İlk olarak Observer bileşenimizi yazalım:
- Subject: Üzerinde oluşan değişikliklerin izleneceği nesnedir.Bu nesneyi izleyecek olana nesneler daha önceden bildirilir. İzleyici nesneler hangi değişiklikleri izlediğinide bildirmek zorundadır.
- Observer: Hangi değişikliklerin kimlere gönderileceğini kendi içerisinde tutar.
- Subscriber : Subject üzerinde olan değişikliklerden haberdar olmak isteyen nesnelerdir. Subscriberlar, Observer a izlemek istediği değişikliklere dair kendini kaydettirir.
Unity için bir örnek üzerinden anlatmaya devam edelim:
Diyelimli sahnemizde bir GameObject nesnesi var ve buna "boss" diyelim. Bir alan içerisinde bunun hareket ettiğini ve duvarlara temas ettiğinde yön değiştirdiğini faredelim. "boss" un sahip olduğu 4 tane de koruması "guard" ı temsil eden GameObjectler olduğunu düşünelim. Bu "guard"ların "boss"un çevresinde onu korumak için hareket ettiğini farz edelim. Bu durumda "boss" ObserverPattern içerisinde "Subject", "guar"lar ise yine ObserverPattern içerisinde "Subscriber" olarak tanımlarız.
ObserverPattern kullanmıyor olsaydık en basit yoldan bu senaryoyu gerçekleştirmek için "boss" için yarattığımız scrit içerisinde kaç tane guard varsa bunları tanımlamamız gerekirdi. Diyelim daha fazla guar olacak bunlarıda bir şekilde bu script e eklemek veya bir liste içerisinde tutmak gerekecekti.
ObserverPattern kullandığımız zaman ise "boss" ve "guard"lar birbirinden habersiz olacak ve guardlar Observer dan "boss" un hareketi ile ilgili bilgi isteyecek. "boss" ise Observer a hareketi ile ilgili bilgi gönderecek.
Şimdi yavaş yavaş Unity için Observer Pattern'ımızı kuralım.
İlk olarak Observer bileşenimizi yazalım:
using System; using System.Collections.Generic; using System.Linq; using System.Text; public class ObservParam { public object data; public object key; } public class Observer { public static Dictionary<object, Dictionary<Action<ObservParam>, BaseBehaviour>> observList = new Dictionary<object, Dictionary<Action<ObservParam>, BaseBehaviour>>(); public static void AddListener(object key, BaseBehaviour obj, Action<ObservParam> callback) { if(!observList.ContainsKey(key)) { Dictionary<Action<ObservParam>, BaseBehaviour> actions = new Dictionary<Action<ObservParam>, BaseBehaviour>(); actions.Add(callback, obj); observList.Add(key, actions); } else { Dictionary<Action<ObservParam>, BaseBehaviour> actions = observList[key]; actions.Add(callback, obj); } } public static void SendMessage(object key) { if(observList.ContainsKey(key)) { ObservParam observParam = new ObservParam(); observParam.data = null; observParam.key = key; Dictionary<Action<ObservParam>, BaseBehaviour> actions = observList[key]; for (int i = 0; i < actions.Count; i++) { BaseBehaviour tmpBehavior = actions.Values.ElementAt(i); tmpBehavior.OnHandlerMessage(observParam, actions.Keys.ElementAt(i)); } } } public static void SendMessage(object key, object param) { if (observList.ContainsKey(key)) { ObservParam observParam = new ObservParam(); observParam.data = param; observParam.key = key; Dictionary<Action<ObservParam>, BaseBehaviour> actions = observList[key]; for (int i = 0; i < actions.Count; i++) { BaseBehaviour tmpBehavior = actions.Values.ElementAt(i); tmpBehavior.OnHandlerMessage(observParam, actions.Keys.ElementAt(i)); } } } public static void RemoveListener(object key, BaseBehaviour obj, Action<ObservParam> callback) { if(observList.ContainsKey(key)) { Dictionary<Action<ObservParam>, BaseBehaviour> actions = observList[key]; for (int i = 0; i < actions.Count; i++) { if(actions.Keys.ElementAt(i) == callback && actions.Values.ElementAt(i) == obj) { actions.Remove(callback); } } } } public static void RemoveAllListeners(BaseBehaviour obj) { foreach (KeyValuePair<object, Dictionary<Action<ObservParam>, BaseBehaviour>> item in observList) { Dictionary<Action<ObservParam>, BaseBehaviour> actions = item.Value; if (actions.ContainsValue(obj)) { for (int i = 0; i < actions.Count; i++) { if (actions.Values.ElementAt(i) == obj) { actions.Remove(actions.Keys.ElementAt(i)); } } } } } }İkinci olarak da Subject ve Subscriberlar için yani "boss" ve "guard"lar için temel oluşturacak Scriptimizi yazalım. Bu Script MonoBehaviour dan türeyecek ve bu sayede Observer'dan gelecek olan güncelemeleri dinleyebileceğiz.
using UnityEngine; using System.Collections; using System.Collections.Generic; using System; public class BaseBehaviour : MonoBehaviour { internal void OnHandlerMessage(ObservParam observParam, Action<observparam> value) { value(observParam); } }Üçüncü olarak "Boss" un hareketleri esnasında göndereceği ve "Guard"ların "Observer"'a bu updateler ile ilgili kayıt oluşturacığı "key"leri oluşturalım.:
public enum BossUpdateKey { MOVE_FORWARD, MOVE_BACKWARD }Dördüncü olarak "Boss" ve "Guard" ile ilgili Scriptlerimizi yazalım.
using UnityEngine; using System.Collections; using System; public class Boss : BaseBehaviour { private void HomeListener(ObservParam obj) { int myParam = (int)obj.data; } // Update is called once per frame void Update() { if (Input.GetKey(KeyCode.UpArrow)) { MoveForward(); } if (Input.GetKey(KeyCode.DownArrow)) { MoveBackward(); } } void MoveForward() { Observer.SendMessage(BossUpdateKey.MOVE_FORWARD, "ileri gidiyorum"); } void BackForward() { Observer.SendMessage(BossUpdateKey.MOVE_BACKWARD, 5); } }
using UnityEngine; using System.Collections; using System; public class Guard : BaseBehaviour { // Use this for initialization void Awake() { Observer.AddListener(BossUpdateKey.MOVE_FORWARD, this, MoveForwardHandler); Observer.AddListener(BossUpdateKey.MOVE_BACKWARD, this, MoveBackwardHandler); } private void MoveForwardHandler(ObservParam obj) { string myParam = obj.data as string; Debug.Log("Boss İleri Gitti"); Debug.Log("Boss: "+ myParam); } private void MoveBackwardHandler(ObservParam obj) { int myParam = (int)obj.data; Debug.Log("Boss Geri Gitti"); Debug.Log("Boss: "+ myParam); } }
Kaydol:
Kayıtlar (Atom)