카메라가 계속 플레이어를 따라다니며, 마우스를 클릭한 곳으로 플레이어가 이동하는 코드를 짜 보았다.
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 한다.
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() 함수에 목적지로 가는 기능을 추가한다.
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()로 바꾸었다.