8. 캐릭터 생성 이벤트

2013. 7. 9. 01:10게임 개발/Unity

게임이 실행되었을 때, 캐릭터 생성 이벤트가 발생을 하고, 캐릭터 이동 이벤트 발생 몹을 만나서 전투를 할 때 자동으로 공격 하고, 사망 이벤트가 발생한다. 그래서 만들어 보자..

 

우선 이벤트를 핸들링을 하는 클래스를 만든다. (이벤트 매니저) 

Singleton<EventManager> 을 상속 받아서 이벤트 클래스를 만든다.

이벤트 매니저를 사용하기 위해서 AddListener 를 통해서 이벤트를 등록해줘야 한다.

이벤트의 등록이 필요 없을 경우에는 DetachListener 를 통해서 이벤트를 제거해 준다.

Trigger 이벤트에서 해당되는 이벤트를 전달하는 역활을 한다.

 

Update 함수에서는 이벤트 큐라는 것을 가지고 있다.

이벤트들을 끊어서 적절한 사용을 하게 됩니다.

 

 

1. Singleton을 우선 구현한다
 -  객체를 한번만 생성해주며, 해당 객체를 어디에서나 접근하게 만들어주는 패턴으로 값 저장, 전달에 유용합니다.

 

 -  Singleton 사용
     - 유니티에서는 스크립트가 오브젝트의 컴포넌트로 사용되기 때문에 오브젝트 없이는 스크립트를 사용할 수 없다. 하지만 싱글턴 패턴을 사용하면 스크립트를 오브젝트의 컴포넌트로 연결시키지 않고도 사용할 수 있다. 주로 무언가를 관리하는 매니저 클래스를 구현할때 사용한다.
      - 예를 들어서 className.instance.Dosomething();  이런 형태로...



public class Singleton<T> : MonoBehaviour where T : MonoBehavior

{

Protected static T instance;

// Returns the instance of the singleton

public static T instance

{

    get
{

if(instance == null)
{
           instance = (T) FindObjectOfType(typeof(T));
           if(instance == null)
           {

                     GameObject obj = new GameObject(typeof(T).ToString());
                     instance = obj.AddComponent<T>();
                     // Debug.LogError(“An instance of “ + typeof(T)
               //+ “is needed in the scene, but there is none.”);

}

}
return instance; 

}

}

 

 

2. 본격적인 EventManager 를 만들어 본다.

 

public interface IEventListener

{

           bool HandleEvent(IEvent evt);

}

 

public class IEvent

{

           // who receive this event?

           public GameObject from;

           public GameObject to;

 

           public virtual string getName(){ return null;}

           public virtual string getData(){ teturn null;}

}                                             

 

public class EventManager : Singleton<EventManager>

{

           public bool LimitQueueProcesing = false;

           public flaot QueueProcessTime = 0.0f;

 

           private Hashtbale m_listenerTable = new Hashtable();

           private Queue m_eventQueue = new Queue;

 

           void Start()

           {

           //EventManager should not be destroyed even though it is singleton,
           //it still needs to call DontDestoryOnLoad()

                     DontDestoryOnLoad(this);

           }

 

           //Add a listener to the event manager that will receive any events of the supplied event name

           public bool AddListener(IEventListener listener, string eventName)

           {

                     if(listener == null || eventName == null)

                     {

                     Debug.Log(“Event Manager: AddListener failed due to no listener or event name specified.”);

                     Return false;

                     }

                     if(!m_listenerTable.ContainKey(eventName))

                                m_listenerTable.Add(eventName, new ArrayList());

                     ArrayList listenerList = m_listenerTable[eventName] as ArrayList;

                     if(listenerList.Contains(listener))

                     {

                                Debug.Log(“Event Manager: Listener : “ + listener.GetType().ToString() + “ is already in list for event : “ + eventName);

                                return false;       //listener already in list.

                     }

                     ListenerList.Add(listener);

                     return true;

           }


           /// Remove a listener from the subscribed to event.

           public bool DetachListener(IEventListener listener, string eventName)

          {

           if (!m_listenerTable.ContainsKey(eventName))

              return false;

 

           ArrayList listenerList = m_listenerTable[eventName] as ArrayList;

           if (!listenerList.Contains(listener))

               return false;

 

           listenerList.Remove(listener);

           return true;

           }

 

           //Trigger the event instantly, this should only be used in specific circumstances,

           //the QueueEvent function is usually fast enough for the vast majority of uses.

           public bool TriggerEvent(IEvent evt)

           {

                     String eventName = evt.GetName();
                     if(!m_listenerTable.ContainsKey(eventName))

                     {

                                Debug.Log(“Event Manager: Event \”” + eventName + “\” triggered has no listeners!”);

                                Return false;      //No listeners for event so ignore it.

                     }         

                     ArrayList listenerList = m_listenerTable[eventName] as ArrayList;

                     Foreach(IEventListener listener in listenerList)

                     {

                                if(listener.HandleEvent(evt))

                                {

                                          //should send event all registered listener.

                                }

                     }

                     return true;

           }

           //Every update cycle the queue is processed, if the queue processing is limited,

           // a maximum processing time per update can be set after which the event will have

           // to be processed next update loop.

           void Update()

           {

                     float timer = 0.0f;

                     while(m_eventQueue.Count > 0)

                     {

                                if(LimitQueueProcesing)

                                {

                                          if(timer > QueueProcessTime)

                                                     return;

                                }

                                IEvent evt = m_eventQueue.Dequeue() as IEvent;

                                If(!TriggerEvent(evt))

                                          Debug.Log(“Error when processing event: “ + evt.GetName());

                                if(LimitQueueProcessing)

                                          timer += time.deltaTime;

                     }

           }

           //Called before the application is stopping.

           public void OnApplicationQuit()

           {

                     m_listenerTable.Clear();

                     m_eventQueue.Clear();

           }

}

 

3. EventSend 에 대해서 정리

 

public class TestEvent : IEvent

{

           public float val = 1.0f;

          

           public override string GetName()

           {

                     return this.GetType().ToString();

           }

}

 

public class EventSend : MonoBehaviour

{

           bool sent = false;

          

           // Use this for initialization

           void Start ()

           {

          

           }

          

           // Update is called once per frame

           void Update ()

           {

          

                     if (sent == false)

                     {

                         TestEvent evt = new TestEvent();

                                evt.from = this.gameObject;

                                evt.val= 2.0f;

                                EventManager.Instance.QueueEvent(evt);

                               

                                sent = true;

                     }

           }

}

 

4. Event Receive 에 대해서도..

 

public class EventRecieve : MonoBehaviour, IEventListener

{

 

           // Use this for initialization

           void Start ()

           {

               EventManager.Instance.AddListener(this as IEventListener, "TestEvent");

           }

          

           void OnDestroy()

           {

                     EventManager.Instance.DetachListener(this as IEventListener, "TestEvent");

           }

          

           // Update is called once per frame

           void Update ()

           {

          

           }

          

           public bool HandleEvent(IEvent evt)

    {

        string strEvt = evt.GetName();

 

        if (strEvt == "TestEvent")

        {

                                Debug.Log ("TestEvent sent from: " + evt.from.gameObject.name);

                               

                                TestEvent e = evt as TestEvent;

                                Debug.Log ("TestEvent value: " + e.val.ToString());

                               

                                return true;

                     }

                    

                     return false;

           }

          

}

 

 

활용 팁

 

1.     Unity3D에서는 게임 실행 중에 리소스를 로딩해서 게임 오브젝트의 인스턴스를 생성할 수 있다.

2.     GameObject instance = Instantiate(Resources.Load(“enemy”,typeof(GameObject)));

 

3.     로딩한 prefab의 인스턴스를 생성하기 위해서는 GameObject.Instantiate()을 사용한다.
Instantiate
호출로 인스턴스를 생성하는 것은 비용이 많이 드는 작업이므로 모바일 디바이스에서는 Instantiate 를 호출할 때에는 주의해야한다. 예를 들어 플레이 중 빈번한 Instantiate 호출은 플레이시 프레임 저하의 원인이 될 수 있으므로 미리 instantiate 한 오브젝트를 사용하는 것이 좋다

.

4.     게임 플레이시 필요한 게임 오브젝트들은 Scene 로딩시 미리 생성해서 플레이시 사용하는 것이 좋다.
또한 이펙트 처리를 위한 게임 오브젝트의 인스턴스들과 같이 생성과 삭제가 빈번하게 일어나는 오브젝트들은 Destroy를 호출해서 삭제하지 말고 사용이 끝나면 해당 게임 오브젝트들을 비활성화고 다시 사용해야 할 때 Instantiate 를 호출 하지 말고 활성화 상태로 변경해서 사용하는 방법이 훨씬 빠른 처리가 가능한 방법이다.

 

메시지 전달을 이용한 게임 이벤트 처리 메커니즘 및 게임 확장에 따른 메시지 추가 방법에 대한 이해 필요!!