Raycast 수업내용을 복습하다가,
캐릭터를 마우스로 클릭 이동시에 내가 마우스 클릭한 타겟포인트쪽으로 회전과 함께 애니메이션이 플레이되는 것을, 몰랐기에, 마우스 클릭이동 소스코드 예제를 찾아보았다.
먼저 마우스 클릭 이동의 원리를 살펴보자
마우스 클릭지점은 2차원(x,y);
원하는 지점은 3차원(x,y,z);
마우스를 클릭하는 순간의 마우스 커서 위치는 x와 y로만 나타난다.
이상태에서는 캐릭터를 우리가 목표한 곳으로 이동시킬 수가 없게 된다.
마우스 커서의 위치를 이용해서 실제 3차원 공간의 좌표를 얻어 오기 위한 방법을 고민해야 된다.
마우스로는 평면화면을 클릭, 나의 눈이 바라보는 최종목표 지점을 파악
플레이어의 눈으로 부터 마우스 클릭지점을 관통하는 가상의 레이저 광선 같은 것을 발사하면 된다.
플레이어 눈 역할을 하는 것은 카메라, 카메라로부터 마우스 클릭 지점을 관통하는 가상의 레이저 광선
을 쏘는 식으로 우리는 마우스 클릭 지점의 2차원 좌표를 게임 공간의 3차원 좌표로 변환할 수가 있다.
transform.LookAt(target)
target의 position 정보가 있고 이 위치를 향해 바라보고 싶다면 위와같이 LookAt을 사용할 수 있다.
하지만 이는 한번에 회전하므로 천천히 targer을 향해 회전하도록 하고 싶다면 아래와 같이
RotateTowards를 사용한다.
transform.rotation = QuQuaternion.RotateTowards(transform.rotation, target.position - transform.position, speed)
찾아본 소스코드 예제에서는
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Control : MonoBehaviour
{
private Behavior behavior; // 캐릭터의 행동 스크립트
private Camera mainCamera; // 메인 카메라
private Vector3 targetPos; // 캐릭터의 이동 타겟 위치
void Start()
{
behavior = GetComponent<Behavior>();
mainCamera = GameObject.Find("Main Camera").GetComponent<Camera>();
}
void Update()
{
// 마우스 입력을 받았 을 때
if (Input.GetMouseButtonUp(0)) //Control에서 마우스입력을 받고 회전시키고 이동시킨다.
{
// 마우스로 찍은 위치의 좌표 값을 가져온다
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
//RaycastHit 선언
RaycastHit hit;
//Physics.Raycast(Ray 원점, Ray 방향, 충돌 감지할 RaycastHit, Ray 거리(길이))
//맨 마지막에 있는 Ray 거리(길이)를 넣지 않아도 되는데, 넣지 않으면 무제한으로 나아감
//아래 코드를 봤을때는 방향 생략가능한 것으로 보여짐
if (Physics.Raycast(ray, out hit, 10000f))
{
targetPos = hit.point;
}
}
// 캐릭터가 움직이고 있다면
if (behavior.Run(targetPos)) //targetPos는 마우스가 찍힌 스크린좌표를 월드좌표 환산한 벡터값
{
// 회전도 같이 시켜준다
behavior.Turn(targetPos);//targetPos는 마우스가 찍힌 스크린좌표를 월드좌표 환산한 벡터값
}
else
{
// 캐릭터 애니메이션(정지 상태)
behavior.SetAnim("idle@loop");
}
}
}
|
Control 스크립트
1. Update함수를 통해 주기적으로 마우스의 입력을 감지한다.
2. 마우스의 입력이 감지되었다면 현재 마우스의 위치를 캐릭터가 이동 할 좌표값으로 변환한다.
3. Behavior 스크립트에 이동하고자 하는 좌표값을 전달하여 실제 이동시키고[Run], 이동하고 있다면[true] 회전도 같이 시킨다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Behavior : MonoBehaviour
{
public float speed = 2.0f; //이동 속도를 정해줌
private Rigidbody rigid; //중력 적용
public Animation anim; //애니메이션을 가져오기 위해
void Awake()
{
rigid = GetComponent<Rigidbody>(); //중력 적용 컴포넌트 가져옴
}
public bool Run(Vector3 targetPos)
{
// 이동하고자하는 좌표 값과 현재 내 위치의 차이를 구한다.
float distance = Vector3.Distance(transform.position, targetPos);
if (distance >= 0.02f) // 차이가 아직 있다면
{
// 캐릭터를 이동시킨다.
transform.localPosition = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);
SetAnim("run@loop"); // 걷기 애니메이션 처리
return true; //Control 스크립트에서, 이동처리를 해줄 것이기 때문에, bool값을 반환
}
return false; //위와 마찬가지.
}
public void Turn(Vector3 targetPos)
{
// 캐릭터를 이동하고자 하는 좌표값 방향으로 회전시킨다
Vector3 dir = targetPos - transform.position; //방향값을 계산하여 dir에 넣어둠
Vector3 dirXZ = new Vector3(dir.x, 0f, dir.z); //위에서 계산한 방향값에서 회전을 담당하는 x와 z값만 가져옴
//Quaternion.LookRotation(벡터값) : 쉽게 얘기해서 target을 기준으로 회전한다.
Quaternion targetRot = Quaternion.LookRotation(dirXZ);
//Rigibody의 강체를 . rotation 으로 변환하면 다음 물리 시뮬레이션 단계 후에 변환이 업데이트됩니다.
//Transform을 사용 하여 회전 을 업데이트하는 것보다 빠릅니다 .
rigid.rotation = Quaternion.RotateTowards(transform.rotation, targetRot, 1000.0f * Time.deltaTime);
}
public void SetAnim(string name)
{
this.anim = this.gameObject.GetComponent<Animation>();
anim.Play(name);
}
}
|
Behavior 스크립트는
Control 스크립트에 의해 실행되는 스크립트인데 분석해 보면
1. Control 스크립트에 의해 Run 함수가 실행된다.
2. 이동 좌표를 전달 받는데 캐릭터의 위치가 이동하고자 하는 위치와 근접하다면 이동을 하지 않고
3. 근접하지 않다면 해당 방향으로 이동시킨다.
4. 이동하고 있다면 true, 이동하고 있지 않다면 false를 리턴하여 Control 스크립트에게 내가 정지상태인지 이동상태인지 알려준다.
5. Turn(회전) 함수도 이동하고자 하는 방향으로 캐릭터를 회전시켜준다.
@@@@
Run함수에서 Vector3.MoveTowards를 함수를 사용하였는데
이 함수를 사용하면 캐릭터가 일정한 속도로 해당 위치로 이동하고,
Vector3.Lerp함수를 사용하면 해당 좌표로 속도를 내서 움직이다가 도착지점에 근접했을 때 서서히 느려진다.
@@@@
위의 코드를 적용했을시에 글의 작성자분의 참고사항이다.
간단한 캐릭터 오브젝트를 하나 생성하고 캐릭터 오브젝트에 아래와 같은 두개의 스크립트를 붙여넣는다.
- Control.cs: 마우스나 키보드의 입력을 받아 캐릭터에게 명령을 내리는 스크립트
- Behavior.cs: 실제 캐릭터의 행동을 담당하는 스크립트
스크립트를 분리한 이유는 캐릭터가 여러개 존재할 때, 내 자신의 캐릭터만 움직이고 싶다면 내 자신의 캐릭터에만 Control.cs만 활성화 해주고 다른 캐릭터들은 비활성화 해주면 내 캐릭터만 깔끔하게 조종 가능하기 때문이다.
@@@@
여기서 한가지 더 안사실은 collider의 크기또한 캐릭터 이동에 영향을 미친다는 것이다.
Box collider 컴포넌트를 붙였을 시에 박스의 크기가 적절하지 않다면, 캐릭터가 부르르 떨면서 왼쪽, 오른쪽으로 자유 회전하는 것을 확인했다.
또한 Constraints 속성에,
Freeze Position, Freeze Rotation가 있는데, Freeze Rotation의 x값을 고정시켰다.
실행화면
참고..
[Unity] 마우스 클릭한 지점으로 캐릭터 이동시키기
대부분 유니티 캐릭터 이동 예제를 보면 키보드의 입력을 받아 이동시키는 예제들이 많은데, 마우스로 캐릭터를 이동시키는 예제를 작성해보려 한다. 준비 과정 간단한 캐릭터 오브젝트를 하나
cjwoov.tistory.com
'Unity > Problems' 카테고리의 다른 글
대리자 본문은 대리자를 불러오기 전에 정의를 해주어야한다. (0) | 2020.06.18 |
---|---|
2020-05-27 RigidBody 중력의 역습 (0) | 2020.05.27 |
MainCam과 UICam의 설정문제 (0) | 2020.05.22 |
2020-05-18 유니티 복습 (파일 입출력, 람다식, 대리자) (0) | 2020.05.18 |
2020-05-18 유니티 파일 입출력... (0) | 2020.05.18 |