Chapter 13-5. 미니 RPG : 타겟팅 락온

Date:     Updated:

카테고리:

태그:

인프런에 있는 Rookiss님의 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click

Chapter 13. 미니 RPG 만들기

🚀 타겟팅 락온

Cursor.Auto로 하면 녹화에 커서가 안잡혀서 Cursor.ForceSoftware로 잠시 바꾸고 녹화했더니 커서가 짱 크다..

image

목적지가 땅으로 찍혀있던 상태라면 마우스를 꾹 누르고 있는 상태에서 마우스를 움직이면 플레이어가 그 커서의 방향으로 따라서 계속 이동한다.

image

그러나 목적지가 보스로 찍혀있느 상태라면 마우스를 누르고 마우스를 움직여도 플레이어는 이에 반응하지 않고 보스로 달려간다.

마우스를 안 누르고 있던 상태에서 처음 누른(PointDown) 곳이 목적지가 된다는 사실.


📜Define

    public enum MouseEvent
    {
        Press,
        PointerDown,  // 마우스 뗀 상태에서 처음 눌렀을 때
        PointerUp,  // 마우스 누르고 있던 상태에서 처음 뗏을 때
        Click,
    }
  • Press : 누르는 동안
  • PointerDown : 안 누르고 있던 상태에서 처음으로 눌렀을 때
  • PointerUp : 0.2초 이상 꾹 누르고 있던 상태에서 처음으로 뗏을 때
    • 꽤 누르고 있다가 뗐을 때
  • Click : 0.2초 이하로 누르고 있던 상태에서 처음으로 뗏을 때
    • 말 그대로 클릭 수준. 찰나만 누르고 뗐을 떄


📜InputManager

public class InputManager
{
    public Action KeyAction = null;
    public Action<Define.MouseEvent> MouseAction = null;

    bool _pressed = false;
    float _pressedTime = 0;

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

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

        if (MouseAction != null)
        {
            if (Input.GetMouseButton(0)) // PointerDown -> Press
            {
                if (!_pressed) // 한번도 눌렀던적이 없었는데 클릭 들어온거면 
                {
                    MouseAction.Invoke(Define.MouseEvent.PointerDown);
                    _pressedTime = Time.time; // start 이후 경과 시간 (구분만 할 수 있으면 됨)
                }
                MouseAction.Invoke(Define.MouseEvent.Press); // 비효율적일 수 있음(이벤트 발생)
                _pressed = true;
            }
            else // Click(금방 뗏을 때) -> PointerUp(좀 오래 눌려있다가 뗏을 때)
            {
                if (_pressed)  // 클릭 이벤트는 안들어왔는데 눌린 상태였었다면
                {
                    if (Time.time < _pressedTime + 0.2f) // 0.2초 내에 뗐을때
                        MouseAction.Invoke(Define.MouseEvent.Click);
                    MouseAction.Invoke(Define.MouseEvent.PointerUp);
                }
                _pressed = false;
                _pressedTime = 0;
            }
        }
    }
  • MouseAction : Define.MouseEvent 을 인수로 받는 함수만 등록 가능한 액션. 📜PlayerController에서 이 인수가 무엇인지에 따라 다르게 동작하도록 할 것.
  • _pressedTime : Click 과 PointerUp 을 구분하기 위해 누르는 시간을 샐 것이다. 0.2 초 이하로 누르면 Click, 0.2 초 이상으로 누르면 PointerUp 로 인식되게끔.
  • 마우스 클릭 발생 ⭕ if (Input.GetMouseButton(0))
    • if (!_pressed) 👉 한번도 눌렀던적이 없었는데 클릭 들어온거면 PointerDown
      • 이제부터 누르는 동안의 시간인 _pressedTime 타이밍을 시작해야 한다. Time.time은 Start() 함수 시작 후 실행 시간이다. 현재 플레이한 초 단위의 시간이라고 생각하면 될 것 같다. Time.time < _pressedTime + 0.2f 로 0.2초 이상 눌렀는지 아닌지를 비교하는데 쓸거라 Time.time 이용한 것이다.
  • 마우스 클릭 발생 ❌
    • if (_pressed) 👉 방금까지 누르고 있더 상태였다면
      • 누른지 0.2초 이내 Click
      • 누른지 0.2초 이상 PointerUp
      • _pressed_pressedTime 리셋

누르는 동안엔 MouseAction.Invoke(Define.MouseEvent.Press); 로 인해 매 프레임마다 이벤트를 발생시킬 수 있으니 성능상 비효율적일 수도 있다. Update문에서 Input.GetMouseButton


📜PlayerController

	void UpdateMoving()
	{
		// ...
			if (Physics.Raycast(transform.position + Vector3.up * 0.5f, dir, 1.0f, LayerMask.GetMask("Block")))
			{
				if (Input.GetMouseButton(0) == false) //
					State = PlayerState.Idle;
				return;
			}
		}
	}

마우스를 꾹 누르고 있는 상태면 (그러니까 Input.GetMouseButton(0)true 이면) 커서가 “Block”에 있더라도 달리는 상태를 유지하도록 한다.


    int _mask = (1 << (int)Define.Layer.Ground) | (1 << (int)Define.Layer.Monster);

    GameObject _lockTarget;

	void OnMouseEvent(Define.MouseEvent evt)
	{
		switch (State)
		{
			case PlayerState.Idle:
				OnMouseEvent_IdleRun(evt);
				break;
			case PlayerState.Moving:
				OnMouseEvent_IdleRun(evt);
				break;
			case PlayerState.Skill:
				{
					if (evt == Define.MouseEvent.PointerUp)
						_stopSkill = true;
				}
				break;
		}
	}

	void OnMouseEvent_IdleRun(Define.MouseEvent evt)
	{
		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;
		}
	}
  • PointerDown일 때 (처음 누른 순간)
    • if (raycastHit) 몬스터 혹은 땅에 화면클릭 Raycast 가 충돌했을 때
      • 클릭한 곳으로 이동해야 한다. _destPos, State 업데이트
        • 몬스터를 클릭했을 때
          • _lockTarget에 몬스터 오브젝트 저장
        • 땅 클릭했을 때
          • _lockTarget null
  • Press일 때 (누르는 동안)
    • 몬스터 타겟인 상태라면 if (_lockTarget != null)
      • 누르고 있는 동안에도 몬스터를 향해 가야한다. (위 gif 참고)
    • 땅 타겟인 상태라면
      • 누르고 있는 동안이더라도 커서가 향하는 곳으로 가야 한다.


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Unity Lesson 2 카테고리 내 다른 글 보러가기

댓글 남기기