[Unity3D] 조이스틱으로 캐릭터 조종하기. [Part 1]
※ 주의
이 글은 아마추어가 개인적으로 생각하여 작성하는 것으로, 이곳에 나오는 내용을 맹신하지 않는것을 당부드립니다.
Menu
1. 조이스틱 만들기.
2. 조이스틱의 벡터를 받아 캐릭터를 회전 및 이동 시키기.
완성작 미리보기
1. 조이스틱 만들기.
1). 이미지 준비.
- 조이스틱의 배경 이미지.
- 조이스틱 이미지.
2). 캔버스 준비.
UI이미지를 따로 관리해주는 객체가 있다.
하이러키창에서 마우스 오른쪽버튼을 클릭해 보면 UI라는 메뉴가 있는데,
이 메뉴안에 있는 여러가지 목록들을 선택하면 목록에 있는 객체가 생성된다.
만약 하이러키창에 캔버스가 없으면 캔버스를 자동으로 생성시키고 캔버스의 자식으로
우리가 선택한 목록을 생성시킨다.
더불어 EventSystem이라는 객체도 생성시키는데, 이 객체는 각종 UI이벤트에 필요한 객체이다.
이객체는 우리가 따로 건드릴 필요는 없다.
이미지를 2개 생성시킨다.
첫 번째 이미지의 이름은 JoyStickBackGround
두 번째 이미지의 이름은 JoyStick
그리고 객체를 하나씩 선택해서 이미지를 넣자.
2개의 이미지를 겹쳐 한쪽 구석에 이쁘게 정리하도록 하자.
정리가 끝났으면
JoyStick을 배경의 자식으로 넣는다.
하이러키창에 조이스틱 객체를 누르고 Add Componenet를 누른다.
그리고 Event Trigger라고 검색하면 하나의 컴포넌트가 나온다.
추가하도록 하자.
이 컴포넌트에는 UI에 대하여 여러가지 이벤트를 수행할 수 있다.
그 중에서 우리가 사용할 것은 드래그와 끝 드래그 이다.
이러한 컴포넌트를 조이스틱 객체에다 만든 이유는
조이스틱객체를 터치하여 움직이게 할 것이기 때문이다.
드래그와 드래그 끝 2개를 추가시켜주자.
다음은 스크립트를 작성하도록 하자.
스크립트의 이름은 JoyStick이다.
이 스크립트는 JoyStickBackGround에 넣도록 하자.
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 53 | using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public class JoyStick : MonoBehaviour { // 공개 public Transform Stick; // 조이스틱. // 비공개 private Vector3 StickFirstPos; // 조이스틱의 처음 위치. private Vector3 JoyVec; // 조이스틱의 벡터(방향) private float Radius; // 조이스틱 배경의 반 지름. void Start() { Radius = GetComponent<RectTransform>().sizeDelta.y * 0.5f; StickFirstPos = Stick.transform.position; // 캔버스 크기에대한 반지름 조절. float Can = transform.parent.GetComponent<RectTransform>().localScale.x; Radius *= Can; } // 드래그 public void Drag(BaseEventData _Data) { PointerEventData Data = _Data as PointerEventData; Vector3 Pos = Data.position; // 조이스틱을 이동시킬 방향을 구함.(오른쪽,왼쪽,위,아래) JoyVec = (Pos - StickFirstPos).normalized; // 조이스틱의 처음 위치와 현재 내가 터치하고있는 위치의 거리를 구한다. float Dis = Vector3.Distance(Pos, StickFirstPos); // 거리가 반지름보다 작으면 조이스틱을 현재 터치하고 있는곳으로 이동. if (Dis < Radius) Stick.position = StickFirstPos + JoyVec * Dis; // 거리가 반지름보다 커지면 조이스틱을 반지름의 크기만큼만 이동. else Stick.position = StickFirstPos + JoyVec * Radius; } // 드래그 끝. public void DragEnd() { Stick.position = StickFirstPos; // 스틱을 원래의 위치로. JoyVec = Vector3.zero; // 방향을 0으로. } } | cs |
Stick변수는 조이스틱을 움직이기 위해 필요하다.
StickFirstPos변수는 조이스틱의 처음 위치가 들어가 있는데,
조이스틱을 움직이기 위해서는 처음 위치에다가 움직일 거리를 더해줄 필요가 있다.
처음위치 + 방향 * 거리 방식으로 움직여야 한다.
그리고, 드래그하다가 터치를 땠을 때 조이스틱은 원래의 위치로 돌아갈 필요가 있는데,
그 원래에 위치로 돌려주기위한 위치 값 저장 이기도 하다.
JoyVec은 현재 조이스틱에 대한 방향을 저장해줄 벡터 변수이다.
Radius는 배경 그림에 대한 반지름의 크기를 넣을 것이다.
조이스틱이 배경 이미지 바깥으로 넘어가지 못하게 하기 위함이다.
다음은 Drag함수이다.
모든 UI이벤트는 사실 레이캐스트로 작동하고 있다.
그렇기 때문에 이미지에 존재하는 Raycast Tartget을 해제하면 터치 이벤트가 작동하지 않는다.
아무튼, 터치에 대한 정보는 EventSystem에 저장되는데, UI메뉴중 아무거나 생성시키면 같이 생성되는 이유는 그 때문이다.
이 EventSystem에는 터치 정보 말고도 여러가지 정보가 저장되어있다.
그렇기 때문에 그 정보를 꺼내 쓰기 위해서 유징해줄 필요가 있는데,
스크립트에 맵 위에 보면 UnityEngine.EventSystems;이 유징되어 있는것을 볼 수 있다.
조이스틱을 움직이기 위해서는 현재 터치되는 위치가 어디인지 알 필요가 있다.
그 위치에 대한 정보는 BaseEventData에 들어있는데, 이 자료형을 사용하려면 EventSystems가 유징되어있어야 한다.
이벤트 트리거에서 잘 보면 BaseEventData을 인자로 받는것을 볼 수 있다.
베이스 이벤트 데이터를 인자로 받아
그 데이터를 PointerEventData 변수에 형변환 시킨뒤 저장한다.
※ PointerEventData : 마우스 및 터치에 대한 이벤트.
BaseEventData을 이용하고 있기 때문에 터치 포인트에 대해서는 따로 쓰게 된다.
무슨말이냐면 쉽게 말해서 이러한 조이스틱말고 또 다른 버튼이벤트 같은것이 있을 경우
터치 포인터를 공유해서 쓰지않고 따로따로 쓴다는 말이다.
한 줄로 요약해서 멀티터치가 가능하다는 소리다.
나머지 구문들은 스크립트에 주석으로 설명이 되어있기 때문이 생략하겠다.
결과
'Unity3D > Project' 카테고리의 다른 글
[Unity3D] UI - HP, MP 에너바 조절하기. [Part 0] (0) | 2017.03.15 |
---|---|
[Unity3D] 조이스틱으로 캐릭터 조종하기. [Part 2] (10) | 2017.03.13 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 4] (3) | 2017.03.08 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 3] (3) | 2017.03.08 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 2] (0) | 2017.03.07 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 4]
※ 주의
이 글은 아마추어가 개인적으로 생각하여 작성하는 것으로, 이곳에 나오는 내용을 맹신하지 않는것을 당부드립니다.
기능정리
1. 플레이어를 따라오는 카메라.
1.5. 플레이어의 움직임.
2. 마우스 휠 카메라 줌 인,아웃 기능.
3. 마우스 오른쪽 버튼 클릭 후 카메라 회전.
- x,y축 회전
- x축 회전의 한계치 설정.
3. 마우스 오른쪽 버튼 클릭 후 카메라 회전.
Input에는 마우스의 움직임에 대한 정보도 제공해 주고 있다.
"Mouse X" 는 마우스의 좌,우 움직임을,
"Mouse Y" 는 마우스의 상,항의 움직임에 대한 정보를 가지고있다.
마우스 오른쪽 버튼을 누르고 있을 때 카메라의 회전이 가능하게 만들어보자.
벡터변수 Gap을 만들어서 Gap.x값에 Mouse Y값을 축적해보도록 하자.
'Gap.x인데 Mouse X값이 아니냐?' 라고 묻는다면, 아니라고 답변해주고 싶다.
Mouse Y는 상,하에 대한 움직임을 감지한다. 즉, 마우스 오른쪽 버튼을 클릭한 채
위로 올리면 카메라는 밑을 바라보게 되고, 밑으로 내리면 위를 바라보게 해야한다.
이러한 경우를 봤을 때 회전을 이용하는건데, y축 회전이 아닌 x축으로 회전을 가하기 때문에
Gap.x에 Mouse Y값을 축적할 필요가 있다.
※ x축으로 회전하기 때문에 Gap.x에 Mouse Y를 축적시킬 필요가 있다.
Gap.x에 Mouse Y의 양수 값으로 축적하게 된다면 마우스를 위로 올려야지 카메라가 위에서 밑을 바라보는 상황이 될것이다.
그렇기 때문에 -1을 곱해주어 음수값으로 만든다면 마우스 오른쪽 버튼 클릭 후 밑으로 드래그 한다면 카메라가 위에서 밑을 바라보는 상활을 만들수 있다.
※ 반대로 Gap.y에는 Mouse X를 축적해야한다.
이 카메라도 마찬가지로 회전의 최소값과 최대값을 Mathf.Clamp함수를 이용하여 지정할 수 있다.
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 53 54 55 56 57 58 59 60 61 62 63 64 65 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class Axis : MonoBehaviour { public Quaternion TargetRotation; // 최종적으로 축적된 Gap이 이 변수에 저장됨. public Transform CameraVector; public float RotationSpeed; // 회전 스피드. public float ZoomSpeed; // 줌 스피드. public float Distance; // 카메라와의 거리. private Vector3 AxisVec; // 축의 벡터. private Vector3 Gap; // 회전 축적 값. private Transform MainCamera; // 카메라 컴포넌트. void Start() { MainCamera = Camera.main.transform; } void Update() { Zoom(); CameraRotation(); } // 카메라 줌. void Zoom() { Distance += Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed * -1; Distance = Mathf.Clamp(Distance, 5f, 20f); AxisVec = transform.forward * -1; AxisVec *= Distance; MainCamera.position = transform.position + AxisVec; } // 카메라 회전. void CameraRotation() { if (transform.rotation != TargetRotation) transform.rotation = Quaternion.Slerp(transform.rotation, TargetRotation, RotationSpeed * Time.deltaTime); if (Input.GetMouseButton(1)) { // 값을 축적. Gap.x += Input.GetAxis("Mouse Y") * RotationSpeed * -1; Gap.y += Input.GetAxis("Mouse X") * RotationSpeed; // 카메라 회전범위 제한. Gap.x = Mathf.Clamp(Gap.x, -5f, 85f); // 회전 값을 변수에 저장. TargetRotation = Quaternion.Euler(Gap); // 카메라벡터 객체에 Axis객체의 x,z회전 값을 제외한 y값만을 넘긴다. Quaternion q = TargetRotation; q.x = q.z = 0; CameraVector.transform.rotation = q; } } } | cs |
Axis객체 인스펙터 정보.
Quternion.Euler(Gap);
오일러를 통해 축적된 Gap을 넣는다.
이 쿼터니언에는 얼만큼 회전하느냐에 대한 회전 값이 들어있다.
이러한 회전값을 TargetRotation에 초기화 시킨다.
그리고 transform.rotation(Axis객체 자신의 회전 값)에 저장된 회전값을 대입해줘도 되지만,
그렇게 되면 카메라가 서서히 회전하는 효과를 느낄수 없으므로, 쿼터니언의 슬러프 함수를 써서 목표회전을 사용하여
값을 대입 해준다.
Quternion.Slerp(현재 자신의 회전 값, 목표 회전 값, 회전 스피드);
정도로 보면 된다.
목표 회전을 하지 않았을 경우. (Slerp함수를 사용하지 않았을 경우.)
transform.rotation = TargetRotation;
목표회전을 사용한 경우. (Slerp함수를 사용한 경우.)
transform.rotation = Quaternion.Slerp(transform.rotation, TargetRotation, RotationSpeed * Time.deltaTime);
1 2 3 4 5 | Quaternion q = TargetRotation; q.x = q.z = 0; CameraVector.transform.rotation = q; | cs |
새롭게 쿼터니언 변수q를 만들어서 TargetRotation을 대입한 이유는
TargetRotation값을 회손하면 안되기 때문이다.
※ TargetRotation는 카메라를 x,y축을 회적시키는데 필요한 값이다.
쿼터니언변수 q에 x,z값을 0으로 초기화 시킨다.
y값만을 사용할 건데, 잘 생각해보면 현재 이 쿼터니언 값을 카메라의 회전값이다.
카메라의 x,z값을 0으로 초기화 시키고 y값만을 쓴다면 어떻게 될까?
바로 이렇게 된다.
x,z값을 0으로 고정시켰기 때문에 y축에대한 회전을 한다.
지금 회전하는 이 객체는 맨 처음에 만들어 두었던 CameraVector객체이다.
이 객체를 y회전만 시키는 이유는 카메라가 회전했을 때 카메라가 보는 방향에서 플레이어를 자유롭게 조종하기 위함이다.
플레이어는 이 객체(CameraVector)에 벡터값을 가져와서 이동한다.
완성.
'Unity3D > Project' 카테고리의 다른 글
[Unity3D] 조이스틱으로 캐릭터 조종하기. [Part 2] (10) | 2017.03.13 |
---|---|
[Unity3D] 조이스틱으로 캐릭터 조종하기. [Part 1] (6) | 2017.03.10 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 3] (3) | 2017.03.08 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 2] (0) | 2017.03.07 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 1] (0) | 2017.03.06 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 3]
※ 주의
이 글은 아마추어가 개인적으로 생각하여 작성하는 것으로, 이곳에 나오는 내용을 맹신하지 않는것을 당부드립니다.
기능정리
1. 플레이어를 따라오는 카메라.
1.5. 플레이어의 움직임.
2. 마우스 휠 카메라 줌 인,아웃 기능.
3. 마우스 오른쪽 버튼 클릭 후 카메라 회전.
- x,y축 회전
- x축 회전의 한계치 설정.
2. 마우스 휠 카메라 줌 인,아웃
Input에는 마우스 휠에대한 반환값도 제공해주고있다.
Input.GetAxis("Mouse ScrollWheel");
반환값은 float로 반환되며 휠을 위로 굴릴경우 양수의 값이,
밑으로 굴릴경우 음수의 값이 반환된다.
이를활용하여 줌 인,아웃 기능을 수행할 것이다.
카메라맨과 카메라의 거리를 유지해주는 Distance라는 변수에
휠을 위로 굴릴경우 Distance를 감소시켜주어 줌 인 기능을 수행하고,
휠을 밑으로 굴릴경우 Distance를 증가시켜주어 줌 아웃 기능을 수행하여 보자.
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 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class Axis : MonoBehaviour { public float ZoomSpeed; // 줌 스피드. public float Distance; // 카메라와의 거리. private Vector3 AxisVec; // 축의 벡터. private Transform MainCamera; // 카메라 컴포넌트. void Start() { MainCamera = Camera.main.transform; } void Update() { Zoom(); } // 카메라 줌. void Zoom() { Distance += Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed * -1; Distance = Mathf.Clamp(Distance, 5f, 20f); AxisVec = transform.forward * -1; AxisVec *= Distance; MainCamera.position = transform.position + AxisVec; } } | cs |
휠을 위로 굴렸을 때 줌 인 효과를 내고 싶다면 Distance에 값을 그대로 더해주면 안된다.
휠을 위로 굴리면 반환값이 양수 값이기 때문에 Distance는 자연히 커지게 되고
줌 인 효과가 아닌 줌 아웃 효과가 나타나게 된다.
그렇기 때문에 Distance += 휠 값 * 줌 스피드 * -1;
-1을 곱해줌으로써 음수 값으로 만들고 휠을 위로 굴렸을 때 Distance값이 감소하게 된다.
Mathf.Clamp함수는 값을 제한해주는 함수이다.
Mathf.Clamp(Value, Min, Max);
Value는 값을 제한해줄 값을 집어넣고, Min은 그 값의 최소값, Max는 그 값의 최대 값을 지정해 준다.
결과
'Unity3D > Project' 카테고리의 다른 글
[Unity3D] 조이스틱으로 캐릭터 조종하기. [Part 1] (6) | 2017.03.10 |
---|---|
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 4] (3) | 2017.03.08 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 2] (0) | 2017.03.07 |
[Unity3D] RPG게임 카메라 - 줌 인/아웃, 카메라 회전. [Part 1] (0) | 2017.03.06 |
[Unity3D] 캐릭터 움직임, 충돌체크, 물리엔진사용 X [Part 5] (0) | 2017.03.02 |