[Unity] 플레이어를 따라다니는 Camera, 마우스로 플레이어 이동

Jihoon·2022년 3월 17일
0

MMO_Unity

목록 보기
4/22

카메라가 계속 플레이어를 따라다니며, 마우스를 클릭한 곳으로 플레이어가 이동하는 코드를 짜 보았다.

InputManager

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

    bool _pressed = false;

    public void OnUpdate()
    {
        if (Input.anyKey && KeyAction != null)
            KeyAction.Invoke();

        if (MouseAction != null)
        {
            if (Input.GetMouseButton(0))
            {
                MouseAction.Invoke(Define.MouseEvent.Press);
                _pressed = true;
            }
            else
            {
                if (_pressed)
                    MouseAction.Invoke(Define.MouseEvent.Click);
                _pressed = false;
            }
        }
    }
}

MouseAction 이벤트를 추가하고, 마우스 왼쪽 버튼을 누르면 Press를 Invoke, 버튼을 떼는 순간 Click을 Invoke 한다.

PlayerController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

    public class PlayerController : MonoBehaviour
{
    [SerializeField]
    float _speed = 10.0f;

    bool _moveToDest = false;
    Vector3 _destPos;

    void Start()
    {
        Managers.Input.KeyAction -= OnKeyboard;
        Managers.Input.KeyAction += OnKeyboard;
        // Action을 두번 구독하는 경우가 생기지 않도록 먼저 구독을 끊고 다시 구독을 한다.
        Managers.Input.MouseAction -= OnMouseClicked;
        Managers.Input.MouseAction += OnMouseClicked;
    }

    void Update()
    {
        if (_moveToDest)
        {
            Vector3 dir = _destPos - transform.position;
            if (dir.magnitude < 0.0001f)
            {
                _moveToDest = false;
            } // 목적지까지의 거리가 매우 작다면 이동중이라는 상태를 false로 만든다.
            else
            {
                float moveDist = Mathf.Clamp(_speed * Time.deltaTime, 0, dir.magnitude);
                // 목적지 좌표에 도착하고도 계속 rotation을 변경하며 목적지에 가려는 상황을 없애기 위해 
                // 목적지 까지의 거리보다 속도가 높아지면 속도를 0으로 만든다.
                transform.position += dir.normalized * moveDist;

                transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(dir), 10 * Time.deltaTime);
            }
        }
    }

    void OnMouseClicked(Define.MouseEvent evt)
    {
        if (evt != Define.MouseEvent.Click)
            return;

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);

        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 100.0f, LayerMask.GetMask("Wall")))
        {
            _destPos = hit.point;
            _moveToDest = true;
        }
    }
}

InputManager에서 마우스 왼쪽 버튼 입력을 받으면 OnMouseClicked를 실행한다.
저번에 공부한 Raycast를 이용해서 마우스 클릭한 곳의 좌표를 구하고, 그 좌표를 목적지로 설정한다.
Update() 함수에 목적지로 가는 기능을 추가한다.

CameraController

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    [SerializeField]
    Define.CameraMode _mode = Define.CameraMode.Quarterview;

    [SerializeField]
    Vector3 _delta = new Vector3(0.0f, 6.0f, -5.0f); // 플레이어와 카메라 상의 거리

    [SerializeField]
    GameObject _player = null;

    void Start()
    {
        
    }

    void LateUpdate()
    {
        if (_mode == Define.CameraMode.Quarterview)
        {
            RaycastHit hit;

            if (Physics.Raycast(_player.transform.position, _delta, out hit, _delta.magnitude, LayerMask.GetMask("Wall")))
            {
                float dist = (hit.point - _player.transform.position).magnitude * 0.8f;
                transform.position = _player.transform.position + _delta.normalized * dist;
            }
            else
            {
                transform.position = _player.transform.position + _delta;
                transform.LookAt(_player.transform);
            }
        }
    }

    public void SetQuarterView(Vector3 delta)
    {
        _mode = Define.CameraMode.Quarterview;
        _delta = delta;
    }
}

플레이어의 위치에서 카메라의 위치로 Raycast를 하여 만약에 사이에 wall레이어를 갖는 객체(벽)가 있다면 카메라의 위치를 벽 앞으로 이동시킨다. 그게 아니라면 항상 플레이어의 위치에서 (0, 6, -5)만큼 떨어진 위치에 카메라가 위치한다.

LateUpdate() 함수를 사용한 이유는 PlayerController의 Update() 함수가 먼저 실행이 되고 나서 CameraController의 Update()가 실행이 되야 하기 때문에 CameraController의 Update()를 LateUpdate()로 바꾸었다.

profile
클라이언트 개발자 지망생

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN