using Unity.Mathematics; using UnityEngine; using UnityEngine.AI; public class PlayerController : MonoBehaviour { private PlayerStatus _status; private Vector3 _destPos; public enum PlayerState { Idle, Move, Die, Skill, } [SerializeField] PlayerState _playerState = PlayerState.Idle; public PlayerState State { get { return _playerState; } set { _playerState = value; Animator anim = GetComponent(); switch (_playerState) { case PlayerState.Die: anim.SetBool("attack", false); break; case PlayerState.Idle: anim.SetFloat("speed", 0); anim.SetBool("attack", false); break; case PlayerState.Move: anim.SetFloat("speed", _status.MoveSpeed); anim.SetBool("attack", false); break; case PlayerState.Skill: anim.SetBool("attack", true); break; } } } void Start() { _status = gameObject.GetComponent(); Managers.Input.MouseAction -= OnMouseEvent; Managers.Input.MouseAction += OnMouseEvent; } void UpdateIdle() { // 애니메이션 처리 // wait_run_ratio = Mathf.Lerp(wait_run_ratio, 0.0f, 8.0f * Time.deltaTime); // Animator anim = GetComponent(); // anim.SetFloat("speed", 0); } void UpdateMove() { // 몬스터가 내 사정거리보다 가까우면 공격 if(_lockTarget != null) { float dist = (_destPos- transform.position).magnitude; if(dist <= 1.0f) { State = PlayerState.Skill; return; } } // 일반 이동 Vector3 dir = _destPos - transform.position; // 이게 transform.position에 직접 넣을때는 정확도가 좀 높아서 0.001 도 가능했는데 지금은 Move로 간접적인 이동이라서 0.1 정도로 그 정확도를 좀 낮출 필요가 있다. if (dir.magnitude < 0.1f) { State = PlayerState.Idle; } else { NavMeshAgent navMesh = gameObject.GetOrAddComponent(); float moveDist = Mathf.Clamp(_status.MoveSpeed * Time.deltaTime, 0, dir.magnitude); // navMesh.CalculatePath() navMesh.Move(dir.normalized * moveDist); // 이게 앞을 막을 경우 계속 움직이는 모션이 아니라 그 앞에서 멈추게 하기 위해서 Debug.DrawRay(transform.position + Vector3.up * 0.5f, dir.normalized * 1.0f, Color.green, 1.0f); // Debug.DrawRay(transform.position, ray.direction * 100.0f, Color.blue, 1.0f); if(Physics.Raycast(transform.position + Vector3.up * 0.5f , dir, 1.0f, LayerMask.GetMask("Block"))) { if(Input.GetMouseButton(0) == false) State = PlayerState.Idle; return; } // transform.position += dir.normalized * moveDist; // 그래서 이렇게 부드럽게 회전 Vector3 targetDir = new Vector3(dir.x, 0, dir.z).normalized; if (targetDir != Vector3.zero) { transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(targetDir), 0.15f); } } // 애니메이션 처리 // wait_run_ratio = Mathf.Lerp(wait_run_ratio, 1.0f, 8.0f * Time.deltaTime); // Animator anim = GetComponent(); // anim.SetFloat("speed", _status.MoveSpeed); } void UpdateSkill() { // Animator anim = GetComponent(); // anim.SetBool("attack", true); } void OnHitEvent() { // Animator anim = GetComponent(); // anim.SetBool("attack", false); State = PlayerState.Idle; } void Update() { // UpdateMouseCursor(); switch (State) { case PlayerState.Die: break; case PlayerState.Idle: UpdateIdle(); break; case PlayerState.Move: UpdateMove(); break; case PlayerState.Skill: UpdateSkill(); break; } } // InputManager에서 하고 있긴 한데 마우스가 움직임에 따라 커서가 바뀔테니 이런건 여기서 하는게 좋을거 같아서 // void UpdateMouseCursor() // { // if(Input.GetMouseButton(0)) return; // // Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // // Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.blue, 1.0f); // // RaycastHit hit; // if(Physics.Raycast(ray, out hit, 100.0f, _mask)) // { // if(hit.collider.gameObject.layer == (int)Define.Layer.Monster) // { // // 몬스터 클릭시 공격 처리 // // // 이 두번째 인자가 뭐냐면 보면 이게 16*16짜리 이미지에 커서를 그리면 이 커서 이미지 끝에 맞춰야 하는데 .zero로 하면 이미지의 끝이 아니라 // // 16*16 의 아이콘 레이어의 끝단에 맞게 된다. 그래서 커서 그림에 맞게 좀 옮겨 줘야 한다. // // 세번째 인자는 오토에 맞게 맞춰주는건데 그냥 오토가 편하다. 수동으로 하는건 나중에 필요하면 따로 알아서 학습하는거로 // // Cursor.SetCursor(_cursorAttack, new Vector2(_cursorAttack.width / 5, 0), CursorMode.Auto); // // if(_cursorType != CursorType.Attack) // { // Cursor.SetCursor(_cursorAttack, new Vector2(_cursorAttack.width / 5, 0), CursorMode.Auto); // _cursorType = CursorType.Attack; // } // } // else // { // if (_cursorType != CursorType.Hand) // { // Cursor.SetCursor(_cursorHand, new Vector2(_cursorHand.width / 3, 0), CursorMode.Auto); // _cursorType = CursorType.Hand; // } // } // } // } int _mask = (1 << (int)Define.Layer.Ground) | (1 << (int)Define.Layer.Monster); GameObject _lockTarget; void OnMouseEvent(Define.MouseEvent evt) { // 클릭 뿐 아니라 마우스 누르고 있어도 이동이 가능하게 하기 위해서 일단 날리기 // if (evt != Define.MouseEvent.Click) return; if(_playerState == PlayerState.Die) return; RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.blue, 1.0f); bool raycastHit = Physics.Raycast(ray, out hit, 100.0f, _mask); switch (evt) { case Define.MouseEvent.PointerDown: if (raycastHit) { _destPos = hit.point; State = PlayerState.Move; 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; // _playerState = PlayerState.Move; } else if (raycastHit) { _destPos = hit.point; // _playerState = PlayerState.Move; } break; // case Define.MouseEvent.PointerUp: // _lockTarget = null; // break; } } // void OnKeyboard() // { // if (Input.GetKey(KeyCode.W)) { Move(Vector3.forward); } // else if (Input.GetKey(KeyCode.S)) { Move(Vector3.back); } // else if (Input.GetKey(KeyCode.A)) { Move(Vector3.left); } // else if (Input.GetKey(KeyCode.D)) { Move(Vector3.right); } // _moveToDest = false; // } // void Move(Vector3 vector) // { // transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(vector), 0.15f); // transform.position += vector * (Time.deltaTime * _speed); // } }