Posts 유니티 - Graphic Raycaster 마우스 이벤트 예제
Post
Cancel

유니티 - Graphic Raycaster 마우스 이벤트 예제

Preview


Enter, Exit, Down

2021_0516_PointerEnterExit


Drag

2021_0516_PointerDrag


Drag(Grid)

2021_0516_PointerDragGrid


Source Code


Icon.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Icon : MonoBehaviour
{
    private Image image;
    private int siblingIndex;

    private static readonly Color DefaultColor = Color.white;
    private static readonly Color FocusedColor = Color.red;
    private static readonly Color DownColor = Color.green;

    private void Awake()
    {
        TryGetComponent(out image);
    }

    public void SetOnTop(bool isTrue)
    {
        // 맨 위에 보이기
        if (isTrue)
        {
            siblingIndex = transform.GetSiblingIndex();
            transform.SetAsLastSibling();
        }
        // 원상복귀
        else
        {
            transform.SetSiblingIndex(siblingIndex);
        }
    }

    public void Focus(bool isFocused)
    {
        if (isFocused)
            image.color = FocusedColor;
        else
            image.color = DefaultColor;
    }

    public void Down()
    {
        image.color = DownColor;
    }

    public void Up()
    {
        image.color = FocusedColor;
    }
}


Example_GraphicRaycaster.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

public class Example_GraphicRaycaster : MonoBehaviour
{
    private GraphicRaycaster gr;
    private PointerEventData ped;
    private List<RaycastResult> rrList;

    [SerializeField] private bool gridMove; // 격자 이동 여부
    [Range(1f, 100f)]
    [SerializeField] private float gridUnit = 20f; // 격자 이동 단위
    [SerializeField] private Icon currentIcon; // 현재 마우스 커서가 위치한 곳의 아이콘
    [SerializeField] private Icon dragIcon;    // 드래그 대상 아이콘

    private Transform dragIconTransform;
    private Vector3 beginDragIconPosition;  // 드래그 시작 시 아이콘의 위치
    private Vector3 beginDragMousePosition; // 드래그 시작 시 마우스 커서 위치
    private Vector3 dragOffset;

    private void Awake()
    {
        gr = GetComponentInParent<GraphicRaycaster>();
        ped = new PointerEventData(EventSystem.current);
        rrList = new List<RaycastResult>(4);
    }

    private void Update()
    {
        ped.position = Input.mousePosition;

        OnPointerEnterAndExit();
        OnPointerDown();
        OnPointerDrag();
        OnPointerUp();
    }

    private void OnPointerEnterAndExit()
    {
        // 드래그 상태일 경우 동작 X
        if (dragIcon != null) return;

        var prevIcon = currentIcon;      // 이전 프레임의 아이콘
        currentIcon = RaycastUI<Icon>(); // 현재 프레임의 아이콘

        if (prevIcon == null)
        {
            // 1. Enter
            if (currentIcon != null)
                OnCurrentEnter();
        }
        else
        {
            // 2. Exit
            if (currentIcon == null)
                OnPrevExit();

            // 3. Change
            else if (prevIcon != currentIcon)
            {
                OnPrevExit();
                OnCurrentEnter();
            }
        }

        // ==================== Local Methods ===================
        void OnPrevExit()
        {
            prevIcon.Focus(false);
        }
        void OnCurrentEnter()
        {
            currentIcon.Focus(true);
        }
    }

    /// <summary> 마우스를 누르는 순간 </summary>
    private void OnPointerDown()
    {
        if (currentIcon == null) return;

        if (Input.GetMouseButtonDown(0))
        {
            // 클릭 이벤트
            currentIcon.Down();
            currentIcon.SetOnTop(true);

            // 드래그 설정
            dragIcon = currentIcon;
            dragIconTransform = dragIcon.transform;

            // 드래그 - 시작 위치 기록
            beginDragIconPosition = dragIconTransform.position;
            beginDragMousePosition = Input.mousePosition;
        }
    }

    /// <summary> 마우스 클릭을 유지할 경우 </summary>
    private void OnPointerDrag()
    {
        if (dragIcon == null) return;

        if (Input.GetMouseButton(0))
        {
            dragOffset = Input.mousePosition - beginDragMousePosition;

            // 미동도 하지 않은 경우
            if (dragOffset.sqrMagnitude < 0.1f)
                return;

            // 일반 이동
            if (!gridMove)
                dragIconTransform.position = beginDragIconPosition + dragOffset;

            // 격자 이동
            else
            {
                Vector3 nextPos = beginDragIconPosition + dragOffset;
                nextPos.x = Mathf.Round(nextPos.x / gridUnit) * gridUnit;
                nextPos.y = Mathf.Round(nextPos.y / gridUnit) * gridUnit;

                dragIconTransform.position = nextPos;
            }
        }
    }

    /// <summary> 마우스를 뗄 경우 </summary>
    private void OnPointerUp()
    {
        if (currentIcon == null) return;

        if (Input.GetMouseButtonUp(0))
        {
            currentIcon.Up();
            dragIcon = null;
        }
    }

    /// <summary> UI에 레이캐스트하여 가장 위에 있는 대상 가져오기 </summary>
    private T RaycastUI<T>() where T : Component
    {
        rrList.Clear();
        gr.Raycast(ped, rrList);

        if (rrList.Count == 0)
            return null;

        return rrList[0].gameObject.GetComponent<T>();
    }
}


Download


This post is licensed under CC BY 4.0 by the author.