[Unity] NGUI 드래그앤드롭(Drag & Drop) 시스템

Filed under tutorials, unity | Comments Off

(NGUI Drag & Drop System)

NGUI에서 드래그앤드롭 시스템 제작에 익숙하지 않은 이들을 위해 관련 서적을 번역하면서 접하게 된 방식을 간단히 소개한다. NGUI가 제공하는 Example 11 – Drag & Drop 씬을 보면 관련 컴포넌트를 이용한 드래그앤드롭 시스템을 확인할 수 있다.

DD_01

 

 

여기서 소개할 내용은 UIDrag Object를 이용해서 아이템을 드래그하고, 마우스 이벤트를 통해서 드롭된 아이템을 준비된 프리팹으로 교체하는 간단한 방식이다. 화면에 다음과 같이 두 개의 스프라이트를 만든다. 일종의 아이템 슬롯이라고 하고, 좌측 슬롯(Slot_A)에서 우측 슬롯(Slot_B)으로 아이템을 드래그앤드롭하게 된다.

DD_02

Slot_A 하위에 UIGrid 컴포넌트가 붙어있는 Grid를 생성한다. 이 예제에서는 하나의 아이템만 사용하기 때문에 큰 의미가 없다. 그러나 여러 아이템을 사용할 경우, Grid의 정렬 기능이 필요하다. Gird 하위에 아이템이 되는 스프라이트를 하나 만든다. 다음과 같은 구조가 된다.

DD_03

 

 

이 상태에서 아이템의 프리팹(Z_Itme_Dropped)을 만들어 둔다. 드롭된 아이템을 생성할 때 사용할 원본이 된다.

계속해서 드래그할 수 있는 아이템을 만든다. 게임오브젝트를 드래그할 수 있도록 Box Collider와 UIDrag Object 컴포넌트를 추가한다. 그 다음 드래그앤드롭 과정에서 마우스 이벤트를 처리할 스크립트(Z_Item)를 새로 만들어 추가한다. 아이템의 컴포넌트는 다음과 같은 모습이 된다. 한가지 유의할 점은 UIDrag Object에서 Drag Effect를 사용하면 나중에 아이템을 원위치 시키는 과정에서 문제가 발생한다는 점이다. 여기서는 일단 None으로 설정한다.

DD_04

DD_05

현재 상태에서는 아이템을 드래할 수 있을 뿐이다. 그럼 아이템을 드롭할 수 있도록 우측 슬롯(Slot_B)에 Box Collider를 추가하고 스트립트(Z_DropZone)를 새로 생성해서 추가한다.

DD_06

 

 

스크립트의 내용은 다음과 같다. 우선 OnDrop() 이벤트를 통해 드롭된 게임오브젝트가 아이템인지 확인한다. 아이템이면 드롭된 상태의 아이템으로 교체하고, 실제로 드롭된 게임오브젝트는 제거한다 (여기서는 드롭된 아이템으로 스프라이트를 사용했다. 따라서 아이템이 드롭되면 더 이상의 상호작용은 없다).

public class Z_DropZone : MonoBehaviour {

	public GameObject droppedItemPrefab;

	public void OnDrop(GameObject dropped)
	{
		// 드롭된 게임오브젝트에 Z_Item 컴포넌트가 있는지 확인하다.
		Z_Item droppedItem = dropped.GetComponent<Z_Item>();
		// 컴포넌트가 없다면, 즉 아이템이 아니라면 더 이상 진행할 필요가 없다.
		if(droppedItem == null) return;
		// 드롭된 아이템 프리팹의 인스턴스를 생성한다.
		GameObject newPower = NGUITools.AddChild(this.gameObject,
		                                         droppedItemPrefab);
		// 드롭된 게임오브젝트는 삭제한다.
		Destroy(dropped);
	}
}

유니티를 실행하고 아이템을 드래그한다. 그런데 여전히 드롭은 이뤄지지 않는다. UICamera에서 Debug 옵션을 체크하고 확인한다.

DD_07

 

 

아이템이 Slot_B 위에 있지만 카메라가 여전히 아이템에 붙어있는 충돌체를 감지하고 있다. 즉 아이템의 충돌체가 Slot_B에서 OnDrop() 이벤트의 호출을 막고 있는 것이다.

DD_08

아이템에 연경돼 있는 Z_Item 스크립트로 가서 다음과 같이 OnPress() 이벤트를 작성한다.

public class Z_Item : MonoBehaviour {

	void OnPress(bool pressed){

		// 아이템을 누르고 있는 동안은 충돌체를 비활성화한다.
		collider.enabled = !pressed;
        }
}

스크립트를 저장한다. 이제 아이템의 충돌체가 비활성화되면서 Slot_B, 즉 드롭할 영역의 충돌체를 감지한다. 아이템을 제대로 드롭할 수 있다.

DD_09

그럼 마지막으로 Slot_B가 아닌 공백이나 Slot_A에 드롭했을 때, 아이템을 원래 위치로 복귀시키는 
부분을 처리한다. Z_Item 스크립트를 다음과 같이 수정한다. 
public class Z_Item : MonoBehaviour {

	void OnPress(bool pressed){

		// 아이템을 누르고 있는 동안은 충돌체를 비활성화한다.
		collider.enabled = !pressed;

		// 아이템을 드롭하면,
		if(!pressed) {

			// UICamera가 감지한 충돌체를 찾는다.
			Collider col = UICamera.lastHit.collider;
			// 감지한 충돌체가 없거나, 드롭 영역이 아니면
			if(col == null || col.GetComponent<Z_DropZone>() == null) {
				// 부모인 Grid를 찾아서
				UIGrid grid = NGUITools.FindInParents<UIGrid>(gameObject);
				// 원래 위치로 돌아온다.
				if(grid != null) grid.Reposition();
			}
		}
	}
}

Comments are closed.