유니티 클릭 컴포넌트 (Clickable)

C#/Unity|2019. 9. 14. 18:32

유니티 게임오브젝트의 클릭은 OnMouseUp이나 OnMouseDown같은 콜백함수로 구현되어있다.

하지만 Double Click이나 Long Click같은 로직은 코루틴을 이용해서 구현해야 하는데 

쉽게 사용하기 위해 컴포넌트 방식으로 구현해 보았다. (2D 기반이며 Collider가 있어야한다)

내부로직은 코루틴으로 작동하며 event를 등록하거나 Regist함수를 호출함으로서 사용가능하다.

개선사항은 Clickable 컴포넌트간의 우선순위 설정이 필요할 수도 있겠다. 

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[DisallowMultipleComponent]
[RequireComponent(typeof(Collider2D))]
public class Clickable : MonoBehaviour {
    public static float DOUBLE_INTERVAL=0.2f;
    public static float LONG_INTERVAL=0.8f;

    public bool isOnce = true;
    public bool isDouble;
    public bool isLong;

    public event Action OnOnceClicked;
    public event Action OnDoubleClicked;
    public event Action OnLongClicked;

    private int downCount;
    private float clickTime;

    private Coroutine doubleCoroutine;
    private Coroutine longCoroutine;


    public Clickable RegistInOnce(Action act) {
        isOnce = true;
        OnOnceClicked += act;
        return this;
    }
    public Clickable RegistInDouble(Action act) {
        isDouble = true;
        OnDoubleClicked += act;
        return this;
    }
    public Clickable RegistInLong(Action act) {
        isLong = true;
        OnLongClicked += act;
        return this;
    }
    public Clickable ClearInOnce(Action act) {
        OnOnceClicked = null;
        return this;
    }
    public Clickable ClearInDouble(Action act) {
        OnDoubleClicked = null;
        return this;
    }
    public Clickable ClearInLong(Action act) {
        OnLongClicked = null;
        return this;
    }

    private void OnMouseDrag() {
        clickTime += Time.deltaTime;
    }
    private void OnMouseUp() {
        clickTime = 0f;
    }

    private void OnMouseDown() {
        clickTime = 0f;
        downCount++;

        if(isOnce && !isDouble && !isLong) {
            OnOnceClicked?.Invoke();
            return;
        }
        if(isDouble && doubleCoroutine == null) {
            doubleCoroutine = StartCoroutine(CoWaitDouble());
        }
        if(isLong && longCoroutine == null) {
            longCoroutine = StartCoroutine(CoWaitLong());
        }
    }

    private IEnumerator CoWaitDouble() {
        float startTime = Time.time;
        int curCount = downCount;
        while(true) {
            if(curCount < downCount) {
                OnDoubleClicked?.Invoke();
                break;
            }

            if(startTime + DOUBLE_INTERVAL < Time.time) {
                if(longCoroutine == null) {
                    OnOnceClicked?.Invoke();
                }
                break;
            }
            yield return null;
        }
        doubleCoroutine = null;
    }
    private IEnumerator CoWaitLong() {
        float startTime = Time.time;
        while(true) {
            if(!Input.GetMouseButton(0)) {
            	if (startTime+DOUBLE_INTERVAL<Time.time) {
                    OnOnceClicked?.Invoke();
                }
                break;
            }

            if(startTime + LONG_INTERVAL < Time.time) {
                OnLongClicked?.Invoke();
                break;
            }

            yield return null;
        }
        longCoroutine = null;
    }
}

'C# > Unity' 카테고리의 다른 글

유용한 Unity & C# 관련 링크  (0) 2020.01.19
유니티 이동 컴포넌트 (Mover)  (0) 2019.09.14
유니티 Android native 사운드 적용  (0) 2019.09.14

댓글()