[Unity] 타게팅 락온

타게팅 락온

저번 포스트에서는 마우스를 적 위에 올렸을 때 평소와는 다른 커서가 나오도록 설정했다. 이번 포스트에서는 적을 클릭했을 때의 행동을 정하도록 한다.

땅을 처음 클릭하고 마우스를 누르고 있는 상태에서 포인터를 움직이면 캐릭터가 포인터를 따라 움직여야 한다. 하지만 적을 처음 클릭했다면 마우스를 누르며 포인터를 움직여도 플레이어는 적에게 가도록 하고 싶다. 그러기 위해 먼저 코드를 수정해야 한다.

public enum MouseEvent
{
    Press,
    PointerDown,
    PointerUp,
    Click,
}

Define 클래스의 MouseEvent Enum에는 원래 Press와 Click만 있었는데, 제일 처음 클릭한 오브젝트가 무엇인지 판별하기 위해 PointerDown, PointerUp 두가지 상태를 추가했다.

public void OnUpdate()
{
    if (EventSystem.current.IsPointerOverGameObject())
        return;

    if (Input.anyKey && KeyAction != null)
        KeyAction.Invoke();

    if (MouseAction != null)
    {
        if (Input.GetMouseButton(0))
        {
            if(!_pressed)
            {
                MouseAction.Invoke(Define.MouseEvent.PointerDown);
                _pressedTime = Time.time;
            } // 신규 작성 코드
            MouseAction.Invoke(Define.MouseEvent.Press);
            _pressed = true;
        }
        else
        {
            if (_pressed)
            {
                if (Time.time < _pressedTime + 0.2f)
                    MouseAction.Invoke(Define.MouseEvent.Click); // 신규 작성 코드
                MouseAction.Invoke(Define.MouseEvent.PointerUp);
            }
            _pressedTime = 0; // 신규 작성 코드
            _pressed = false;
        }
    }
}

InputManager 클래스의 OnUpdate() 함수를 수정하였다.
기존과는 다르게 PointerDown, Up을 Invoke하는 코드가 추가되었다.

위와 같은 경우에는 처음 눌렀을 때 PointerDown이 Invoke되고 마우스를 누르고 있는 시간을 잰다. 동시에 Press를 Invoke하며 이후에는 Press만 Invoke한다.

만약 마우스를 누르고 있지 않다면 먼저 위에서 잰 마우스를 누르고 있는 시간이 0.2초 아래라면 Click을 Inovke, 아니라면 PointerUp을 Invoke한다.

int _mask = (1 << (int)Define.Layer.Ground) | (1 << (int)Define.Layer.Monster);
GameObject _lockTarget;
void OnMouseEvent(Define.MouseEvent evt)
{
    if (_state == PlayerState.Die)
        return;

    RaycastHit hit;
    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    bool raycastHit = Physics.Raycast(ray, out hit, 100.0f, _mask);

    switch (evt)
    {
        case Define.MouseEvent.PointerDown:
            {
                if (raycastHit)
                {
                    _destPos = hit.point;
                    _state = PlayerState.Moving;

                    if (hit.collider.gameObject.layer == (int)Define.Layer.Monster)
                    {
                        _lockTarget = hit.collider.gameObject;
                    }
                    else
                    {
                        _lockTarget = null;
                    }
                }
            }
            break;
        case Define.MouseEvent.Press:
            {
                if (_lockTarget != null)
                    _destPos = _lockTarget.transform.position;
                else if (raycastHit)
                    _destPos = hit.point;
            }
            break;
        case Define.MouseEvent.PointerUp:
            _lockTarget = null;
            break;
    }
}

PlayerController의 코드를 수정하였다. switch문을 사용해서 마우스 이벤트에 따라 동작을 구분하였다.

_lockTarget이라는 변수를 추가해서 만약 처음 클릭한 대상이 적이라면 적을 _lockTarget 변수에 저장한다. 이후에 Press 이벤트를 받을 때마다 _lockTarget을 판별해서 _lockTarget이 Null이라면 마우스를 누르는 곳으로 이동, _lockTarget이 있다면 무조건 _lockTarget으로 이동하도록 하였다.

코드를 수정한 뒤 예상한대로 작동하는 것을 확인하였다. 하지만 처음 땅을 클릭하고 이동하는 와중에 적에 마우스를 올리면 커서가 바뀌는데, 이를 수정하도록 한다.

void UpadateMouseCursor()
{
    if (Input.GetMouseButton(0))
        return;
        ...
}            

PlayerController의 UpdateMouseCursor() 함수를 수정하였다. 단순히 만약 마우스를 누르고 있다면 함수를 바로 return하는 것으로 해결하였다. 이제 예상한대로 작동하는 것을 확인하였다.

좋은 웹페이지 즐겨찾기