내가 제작 중인 Lapi라는 게임에서 커서를 NPC나 적에게 갖다대면 커서가 변경되는 것을 구현하고 있었다.
처음에는 Update()에서 마우스 위치로 레이캐스팅을 하며 레이 히트된 오브젝트가 있다면 분기를 통해서 커서를 변경하는 방법을 사용했었다.
하지만 이 방법은 감지할 오브젝트가 없어도 Update()를 통해 매 프레임 호출되기 때문에 최적화 측면에서 성능이 나빴다.
그래서 생각한 것이 '매 프레임 호출되는 것 대신 오브젝트에 들어올 때와 벗어날 때 발생하는 이벤트가 있지 않을까?'였다.
| 이벤트 메서드 | 설명 |
|---|---|
OnMouseEnter() | 마우스가 오브젝트에 진입하면 이벤트 발생 |
OnMouseOver() | 마우스가 오브젝트에 위치하는 동안 이벤트 발생 |
OnMouseExit() | 마우스가 오브젝트에서 벗어나면 이벤트 발생 |
OnMouseUp() | 마우스로 오브젝트를 클릭했다가 떼어낼 때 발생 |
OnMouseDown() | 마우스로 오브젝트를 클릭할 때 발생 |
나는 하나의 오브젝트가 아닌 NPC와 적에 모두 적용시키고 싶었다.
그래서 NPC와 적과 같은 구체화된 객체보다 고수준의 모듈을 만들기로 결정했다.
먼저 추상 클래스 MouseDetector를 선언하여 커서에 대한 기본 동작과 NPC와 적이 구현해야 할 내용들과 필요할 때 구현할 내용을 정의했다.
using UnityEngine;
public abstract class MouseDetector : MonoBehaviour
{
[Header("커서 데이터베이스")]
[SerializeField] private CursorDataBase m_cursor_db;
protected void SetCursor(CursorMode mode)
{
m_cursor_db.SetCursor(mode);
}
protected abstract void OnMouseEnter();
protected virtual void OnMouseExit()
{
SetCursor(CursorMode.DEFAULT);
}
}
그 다음엔 NPC와 적이 각각 부착할 컴포넌트를 구현했다.
using UnityEngine;
public class NPCMouseDetector : MouseDetector
{
private NPC m_npc;
private NameTagPresenter m_name_tag_presenter;
private void Awake()
{
m_npc = GetComponent<NPC>();
}
public void Inject(NameTagPresenter presenter)
{
m_name_tag_presenter = presenter;
}
protected override void OnMouseEnter()
{
SetCursor(CursorMode.CAN_TALK);
var target_position = (Vector2)transform.position + Vector2.up * 3f;
m_name_tag_presenter.OpenUI(m_npc.Code, new System.Numerics.Vector2(target_position.x, target_position.y));
}
protected override void OnMouseExit()
{
base.OnMouseExit();
m_name_tag_presenter.CloseUI();
}
protected virtual void OnMouseDown()
{
m_npc.Interaction();
}
}
using UnityEngine;
public class EnemyMouseDetector : MouseDetector
{
protected override void OnMouseEnter()
{
SetCursor(CursorMode.CAN_ATTACK);
}
}
위의 코드를 DI Container에서 의존성을 주입하는 과정을 거치고 다음과 같은 실행 결과를 얻을 수 있었다.

