Chapter 13-5. 미니 RPG : 타겟팅 락온
카테고리: Unity Lesson 2
태그: Unity Game Engine
인프런에 있는 Rookiss님의 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
Chapter 13. 미니 RPG 만들기
🚀 타겟팅 락온
Cursor.Auto
로 하면 녹화에 커서가 안잡혀서 Cursor.ForceSoftware
로 잠시 바꾸고 녹화했더니 커서가 짱 크다..
목적지가 땅으로 찍혀있던 상태라면 마우스를 꾹 누르고 있는 상태에서 마우스를 움직이면 플레이어가 그 커서의 방향으로 따라서 계속 이동한다.
그러나 목적지가 보스로 찍혀있느 상태라면 마우스를 누르고 마우스를 움직여도 플레이어는 이에 반응하지 않고 보스로 달려간다.
마우스를 안 누르고 있던 상태에서 처음 누른(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) 👉 한번도 눌렀던적이 없었는데 클릭 들어온거면
- 마우스 클릭 발생 ❌
- if (_pressed) 👉 방금까지 누르고 있더 상태였다면
- 누른지 0.2초 이내
Click
- 누른지 0.2초 이상
PointerUp
_pressed
와_pressedTime
리셋
- 누른지 0.2초 이내
- if (_pressed) 👉 방금까지 누르고 있더 상태였다면
누르는 동안엔 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
- 몬스터를 클릭했을 때
- 클릭한 곳으로 이동해야 한다.
- if (raycastHit) 몬스터 혹은 땅에 화면클릭 Raycast 가 충돌했을 때
Press
일 때 (누르는 동안)- 몬스터 타겟인 상태라면 if (_lockTarget != null)
- 누르고 있는 동안에도 몬스터를 향해 가야한다. (위 gif 참고)
- 땅 타겟인 상태라면
- 누르고 있는 동안이더라도 커서가 향하는 곳으로 가야 한다.
- 몬스터 타겟인 상태라면 if (_lockTarget != null)
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기