마우스 입력을 받아 캐릭터 또는 오브젝트를 이동한다.
1. 마우스 입력
마우스 입력은 Input.GetMouseButtonDown(0), Input.GetMouse... 이다.
- 0은 왼쪽 마우스 클릭
- 1은 오른쪽 마우스 클릭
- 2는 가운데 마우스 클릭
2. 화면(Screen)과 레이(Ray)
스크린의 좌표가 있고, 게임 월드의 좌표가 존재한다.
마우스 입력은 게임 월드의 좌표에 직접적으로 클릭을 하는 것이 아니다.
화면(Screen)에 클릭을 하는 것이다. 마우스 클릭으로부터 게임 월드의 좌표를 얻기 위해서는 변환이 필요하다.
유니티는 카메라에서 광선(빛)을 월드로 투영해 접촉한 지점의 월드 좌표를 얻을 수 있다.
Ray ray = Camera.main.ScreenPointToRay(Input.mousePoint);
if(Physics.Raycast(ray, out RaycastHit raycastHit)){
}
Ray는 물리엔진을 사용한다. 충돌을 감지하기 위한 Collider가 없다면 충돌 지점을 알수 없다.
void Update(){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// Ray Draw
Debug.DrawRay(ray.origin, ray.direction * 100.0f, Color.green);
}
Ray는 프로젝트 상에 보이지 않는다. Debug의 DrawRay()를 사용하면, Scene View에서 레이를 보이도록 설정할 수 있다. DrawRay (시작 위치, 방향, 색상)을 나타낸다.
Debug.DrawRay(ray.origin, ray.direction * 100.0f, Color.green);
아래 사진은 카메라로부터 투영된 Ray를 나타낸다. (카메라는 흰색, 녹색 선은 레이다.)
평면(Plane)을 클릭하게 되면 캐릭터가 이동하고, 빈 공간(Empty)을 클릭하면 캐릭터가 이동하지 않는다. 카메라로부터 투영된 레이가 어떠한 게임 오브젝트와도 충돌이 발생하지 않았기 때문이다.
3. 이동 제한
구현된 게임월드에는 이동이 불가능한 지점이 있을 수 있다. 그러나 이동 불가능한 지점이 Collider를 가지고 있어, 레이로부터의 충돌을 감지하고, 캐릭터가 이동을 하게 되는 경우가 발생할 수 있다. 이러한 문제를 해결하기 위해 다양한 방법들이 있다.
그중 하나의 방법으로 Layer 설정이다. 이동이 가능한 지점을 Ground Layer로 설정하고, Ray 충돌을 감지하도록 구현할 수 있다. LayerMask는 레이 캐스팅에 사용할 레이어를 설정한다.
using UnityEngine;
public class Movement : MonoBehaviour{
public LayerMask layerMask;
public float rayDistance = 100.0f;
void Update(){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physcis.Raycast(ray, out RaycastHit raycastHit, rayDistance, layerMask){
// Todo something if ray hit.
}
}
}
4. 마우스 이동 구현
4.1. Quaternion.LookRotation(direction)
Vector3RotateTowards(current, target, , maxRadiansDelta, maxMagnitudeDelta )를 사용해 방향을 구한다.
current은 캐릭터, target은 바라보려고하는 대상, maxRadiansDelta는 각도, maxMagnitudeDelta는 벡터의 크기가 1보다 클 경우 보정하기 위해 사용된다.
Quaternion.LookRotation()은 벡터로 표현되는 상대적인 각도를 Quaternion으로 변경해준다.
using UnityEngine;
public class Movement : MonoBehaviour
{
public float moveSpeed = 10.0f;
public float rotateSpeed = 10.0f;
private Vector3 movePos = Vector3.zero;
private Vector3 moveDir = Vector3.zero;
void Update()
{
if(Input.GetMouseButtonDown(0))
{
// 카메라에서 광선을 마우스 클릭된 곳에 조사한다.
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// 조사 지점에 충돌하는 물체가 있는지 판별한다.
if(Physics.Raycast(ray, out RaycastHit raycastHit))
{
movePos = raycastHit.point;
moveDir = movePos - transform.position;
}
}
// 보는 방향과 목표 방향을 이용해 회전하고자하는 방향을 구한다.
Vector3 newDir = Vector3.RotateTowards(transform.forward, moveDir, rotateSpeed * Time.deltaTime, 0.0f);
transform.rotation = Quaternion.LookRotation(newDir);
transform.position = Vector3.MoveTowards(transform.position, movePos, moveSpeed * Time.deltaTime);
}
}
4.2. Quaternion.Euler(angle)
방향을 구하고, atan2를 이용해 회전각을 구한다.
Quaternion.Euler(angle)은 각도를 Quaternion으로 변경해준다.
using UnityEngine;
public class Movement : MonoBehaviour
{
public float moveSpeed = 10.0f;
private Vector3 movePos = Vector3.zero;
private Vector3 moveDir = Vector3.zero;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// RaycastHit raycastHit;
if (Physics.Raycast(ray, out RaycastHit raycastHit))
{
// 이동 지점
movePos = raycastHit.point;
}
Debug.DrawRay(ray.origin, ray.direction * 100.0f, Color.green);
}
if (movePos != Vector3.zero)
{
// 방향을 구한다.
Vector3 dir = movePos - transform.position;
// 방향을 이용해 회전각을 구한다.
float angle = Mathf.Atan2(dir.x, dir.z) * Mathf.Rad2Deg;
// 회전 및 이동
transform.rotation = Quaternion.Euler(0, angle, 0);
transform.position = Vector3.MoveTowards(transform.position, movePos, moveSpeed * Time.deltaTime);
}
// 현재위치와 목표위치 사이의 거리를 구한다.
float dis = Vector3.Distance(transform.position, movePos);
// 목표지점 도달시 이동지점을 초기화해 추가적인 움직임을 제한한다.
if (dis <= 0.3f)
{
movePos = Vector3.zero;
}
}
}
참조
https://docs.unity3d.com/kr/530/ScriptReference/Vector3.RotateTowards.html
https://gamedevbeginner.com/how-to-convert-the-mouse-position-to-world-space-in-unity-2d-3d/
'유니티 > 기초' 카테고리의 다른 글
유니티 씬(Scene)과 씬 전환 (Scene Transition) (0) | 2020.11.01 |
---|---|
유니티 캐릭터 점프 [기초 6] (0) | 2020.09.13 |
유니티 카메라 이동 및 회전 [기초 5] (1) | 2020.05.05 |
유니티 캐릭터 이동 및 회전 [ 기초 3] (1) | 2020.05.04 |
유니티 오브젝트 회전 [기초 2] (0) | 2020.05.04 |