

구현 자체는 어렵지 않았다. 일정 범위이상 마우스를 이동할 경우 true/false의 bool 값을 만들고 해당 bool 값이 true일 경우에 오브젝트를 변경해주면 된다.
하지만 추가적으로 신경써야하는 것이 몇가지 있었다.

첫번째는 메인뷰의 오브젝트와 서브뷰의 오브젝트의 layer가 다른 것이었다. 메인뷰의 경우 background는 0, object는 1에 생성되는데, 서브 뷰는 background가 10, object는 11에 생성되어야 하기 때문에 오브젝트를 그냥 변경한다고 해결되지 않았다.
그래서 일단 서브뷰의 오브젝트를 따로 생성하여, 해당 오브젝트와 메인 오브젝트가 연결되도록 하는 구조를 사용했다.
두번째는 메인뷰 오브젝트와 서브뷰 오브젝트마다 설정값이 조금씩 달라지는 것이었다. 이동 가능한 오브젝트를 늘릴때마다 어렵지 않게 설정할 수 있는 방법이 필요했고, 프리팹으로 설정할 것이긴 하지만, 유니티 내에서 내가 설정하지 않고도 코드로 캐싱까지 잘 처리되었으면 했다. (하이어라키창에서 설정하는게 많을수록 머지나 풀리퀘하는데 문제가 생기는 것 같다.)
그러기 위해서는 일단 코드 자체를 쉽게 재활용이 가능하고 원하는 부분만 변형을 할 수 있어야 했다.

일단 기능을 전부 들고있는 추상클래스를 만들었다.
공통적으로 사용할 모든 EventSystem을 끌고왔는데, 현재 단계에서는 전부 고정해두고 나중에 사용하지 않는 것들은 없앨 예정이다.
public class FindMousePlace : MonoBehaviour
{
//마우스의 위치를 찾습니다. 서브 데스크로 넘어가면 자동으로 이미지를 변경해줍니다.
public static FindMousePlace instance;
public Vector2 mousePosition;
public bool inSubDesk;
private void Awake()
{
instance = this;
}
void Update()
{
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (mousePosition.x < -504) inSubDesk = true;
else inSubDesk = false;
}
public void MoveObjectToMousePosition(GameObject gameObject)
{
gameObject.transform.position = mousePosition;
}
}
마우스 포지션의 경우 여러 상황에서 찾아야 할 것 같아 하나의 싱글톤으로 만들었다. 실제로 MoveObjectToMousePosition 함수의 경우 매개변수로 받은 오브젝트의 위치를 마우스 포지션과 동일하게 바꿔주는 함수이다.
public abstract class TestDragScript : MonoBehaviour, IBeginDragHandler,
IDragHandler, IDropHandler, IEndDragHandler, IPointerDownHandler, IPointerUpHandler
{
private RectTransform _rectTransform;
private Vector2 defaultPosition;
public GameObject subDeskobject;
public GameObject mainDeskobject;
protected string[] splitname;
Vector2 mousePosition => FindMousePlace.instance.mousePosition;
public void Awake()
{
_rectTransform = GetComponent<RectTransform>();
splitname = this.gameObject.name.Split('_');
}
public virtual void OnBeginDrag(PointerEventData eventData) //드래그 시작할때 한번만 실행
{
}
public virtual void OnDrag(PointerEventData eventData) //마우스를 누른 상태에서 이동할때마다 실행
{
this.gameObject.transform.position =
new Vector2(mousePosition.x - defaultPosition.x, mousePosition.y - defaultPosition.y);
}
public virtual void OnDrop(PointerEventData eventData) //마우스를 누른 상태에서 본인 위에서 드랍하면 실행
{
Debug.Log("test : OnDrop");
}
public virtual void OnEndDrag(PointerEventData eventData) //드래그 끝날 때 한번만 실행
{
Debug.Log("test : OnEndDrag");
}
public virtual void OnPointerDown(PointerEventData eventData) //클릭 시
{
_rectTransform.SetAsLastSibling();
defaultPosition.x = mousePosition.x - this.gameObject.transform.position.x;
defaultPosition.y = mousePosition.y - this.gameObject.transform.position.y;
}
public virtual void OnPointerUp(PointerEventData eventData) //클릭 종료 시
{
}
}
추상클래스로 묶어서 만든 코드는 부모 클래스에서 따로 설정없는 드래그 앤 드롭만 구현했다.
public class MainObjectEvent : TestDragScript
{
private Shadow _shadow;
public GameObject subDeskobjectImage;
private new void Awake()
{
base.Awake();
mainDeskobject = transform.GetChild(0).gameObject;
_shadow = mainDeskobject.GetComponent<Shadow>();
_shadow.enabled = false;
subDeskobject = GameObject.Find("Sub_" + splitname[1]).gameObject;
subDeskobjectImage = subDeskobject.transform.GetChild(0).gameObject;
}
public void Start()
{
subDeskobjectImage.SetActive(false);
}
public override void OnDrag(PointerEventData eventData)
{
base.OnDrag(eventData);
FindMousePlace.instance.MoveObjectToMousePosition(subDeskobject);
mainDeskobject.SetActive(!FindMousePlace.instance.inSubDesk);
subDeskobjectImage.SetActive(FindMousePlace.instance.inSubDesk);
}
public override void OnPointerDown(PointerEventData eventData)
{
base.OnPointerDown(eventData);
_shadow.enabled = true;
}
public override void OnPointerUp(PointerEventData eventData)
{
base.OnPointerUp(eventData);
_shadow.enabled = false;
}
}
Find 함수는 최대한 안쓰는 것이 좋지만, 따로 연결하는 수고 없이도 이름만 맞추면 알아서 붙을 수 있도록 만들었다.
이름은 통일하고, 이름 앞에 Main_ 을 붙이거나 Sub_를 붙여서 같은 이름의 오브젝트를 찾는 방식이다. 객체중에서 같은게 두개 이상 생성될 일이 없기 때문에 이런 방식을 사용했다.