구현한 것
1. 조이스틱으로 캐릭터를 움직이고
2. 화면 터치로 카메라를 움직인다 ( 수평 yaw -캐릭터 주위를 공전, 수직 pitch - 일정 각도까지만 회전)
조이스틱까진 수월하게 구현했는데 터치로 카메라를 제어하는 것이 어려웠다.
모바일 환경에서 터치로 카메라를 어떻게 조종하는가 찾아보면 대부분 getmouseButton 에 raycast를 쏘는 방식으로
구현하는지 터치 구조체를 이용하는 방법은 잘 나오지 않았다
거기에 한손으로 이동 조작을 하면서 다른 손가락 터치로 카메라를 어떻게 제어하는지 코드나 방법을 찾아보았는데
대부분 카메라가 플레이어를 따라다니는 것까지만 구현하는 게 가장 많았고 내가 필요했던 방법은 나오질 않았다..
여차저차 열심히 구글링해서 나오는대로 터치 구조체를 이용하지 않고 getmounsebuttondown(0) 나 IPointer인터페이스로 어찌어찌 만들어보았다.
유니티3D에선 마우스 입력으로 원하는대로 잘 나왔는데 모바일로 빌드하면 영 다른 결과가 나왔다.
위 두방법 사용하면 어딜 누르든 다 터치되는 걸로 인식이 되어서 조이스틱만 눌러봐도 화면이 돌아가는 문제가 생김ㅋㅋ
결국 해결해야하는 문제가 2가지 있었는데
1. 조이스틱 같은 UI를 터치할 시 화면 회전이 되어서는 안된다
2. 조이스틱을 터치하고 드래그하면 계속 조이스틱 입력이 진행되는데
모바일 조이스틱 특성상 조이스틱 범위를 벗어나도 입력되어야하며 그 입력에 화면이 회전되어서는 안된다.
이거 해결하려고 github에서 제스처도 찾아보고 구글링 열심히 해봤는데 코드가 너무 어려웠다...
나중에 더 공부해봐야지..
결국 이것저것 더 검색하다가 유튜브에서 unity fps controller를 검색해서
터치에 관련해서 잘 설명해놓은 FPS 1인칭 시점 구현 영상을 찾아서 따라해보면서 만들어보았다.
따라해보면서 알게된 2가지 문제를 해결하는 방법
1. 조이스틱 같은 UI를 터치할 시 화면 회전이 되어서는 안된다
-> if(!EventSystem.current.IsPointerOverGameObject(i)) : UI면 true를 반환 / 아니면 false를 반환
2. 조이스틱을 터치하고 드래그하면 계속 조이스틱 입력이 진행되는데
모바일 조이스틱 특성상 조이스틱 범위를 벗어나도 입력되어야하며 그 입력에 화면이 회전되어서는 안된다.
-> 화면을 반 나눠서 화면 오른쪽에서만 카메라가 회전되게 만듦
CameraController 코드
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class CameraController : MonoBehaviour
{
[SerializeField] private GameObject player;
[SerializeField] private float speed;
private int rightFingerId;
float halfScreenWidth; //화면 절반만 터치하면 카메라 회전
private Vector2 prevPoint;
private Vector3 originalPos;
public Button btn; // 시점(yaw)을 원상태로 되돌리는 버튼
public Transform cameraTransform;
public float cameraSensitivity;
private Vector2 lookInput;
private float cameraPitch; //pitch 시점
void Start()
{
this.rightFingerId = -1; //-1은 추적중이 아닌 손가락
this.halfScreenWidth = Screen.width / 2;
this.originalPos = new Vector3(0, 0, 0);
this.cameraPitch = 35f;
this.btn.onClick.AddListener(() =>
{
this.transform.eulerAngles = this.originalPos;
});
}
// Update is called once per frame
void Update()
{
this.transform.position = Vector3.Lerp(this.transform.position, this.player.transform.position + new Vector3(0,this.transform.position.y,0), this.speed);
GetTouchInput();
}
private void GetTouchInput()
{
//몇개의 터치가 입력되는가
for (int i = 0; i < Input.touchCount; i++)
{
Touch t = Input.GetTouch(i);
switch (t.phase)
{
case TouchPhase.Began:
if (t.position.x > this.halfScreenWidth && this.rightFingerId == -1)
{
this.rightFingerId = t.fingerId;
Debug.Log("오른쪽 손가락 입력");
}
break;
case TouchPhase.Moved:
//이것을 추가하면 시점 원상태 버튼을 누를 때 화면이 돌아가지 않는다
if (!EventSystem.current.IsPointerOverGameObject(i))
{
if (t.fingerId == this.rightFingerId)
{
//수평
this.prevPoint = t.position - t.deltaPosition;
this.transform.RotateAround(this.player.transform.position, Vector3.up, -(t.position.x - this.prevPoint.x) * 0.2f);
this.prevPoint = t.position;
//수직
this.lookInput = t.deltaPosition * this.cameraSensitivity * Time.deltaTime;
this.cameraPitch = Mathf.Clamp(this.cameraPitch - this.lookInput.y, 10f, 35f);
this.cameraTransform.localRotation = Quaternion.Euler(this.cameraPitch, 0, 0);
}
}
break;
case TouchPhase.Stationary:
if (t.fingerId == this.rightFingerId)
{
this.lookInput = Vector2.zero;
}
break;
case TouchPhase.Ended:
if (t.fingerId == this.rightFingerId)
{
this.rightFingerId = -1;
Debug.Log("오른쪽 손가락 끝");
}
break;
case TouchPhase.Canceled:
if (t.fingerId == this.rightFingerId)
{
this.rightFingerId = -1;
Debug.Log("오른쪽 손가락 끝");
}
break;
}
}
}
}
|
터치 단계는 열거형으로 5단계로 구성되어 있는데 각 단계마다 어떻게 할 것인지 구성하면 된다.
1. Began - 터치가 시작되었을 때
2. Moved - 터치하면서 움직일 때(드래그 할때)
3. Stationary - 터치는 하는데 한 지점에 머무를 때
4. Ended - 터치하다 손 땠을 때
5. Canceled - 전화가 오거나 다른 어플이 켜지는 등 상황에서 터치가 입력되지 못할 때
기타
t.position : 터치가 현재 입력되어있는 좌표
t.deltaPosition : 현재 터치와 이전 터치 좌표의 차이
Mathf.Clamp(this.cameraPitch - this.lookInput.y, 10f, 35f);
특정값이 최소값과 최대값을 넘어지가지 않도록 제한한다.
하이어라키 구성
동영상
참고
Unity - 스크립팅 API: Touch
Devices can track a number of different pieces of data about a touch on a touchscreen, including its phase (ie, whether it has just started, ended or moved), its position and whether the touch was a single contact or several taps. Furthermore, the continui
docs.unity3d.com
'팀프로젝트 > R&D' 카테고리의 다른 글
2020.06.15. 조명 + 낮, 밤 Cycle 만들기 (0) | 2020.06.16 |
---|---|
2020.06.14. Emission 모바일에 적용시키기 (0) | 2020.06.14 |
2020.06.14. 낮,밤 / 조명 (버튼) - Emission 이 쉐이더 눌러야 적용되던 것 해결 (0) | 2020.06.14 |
2020.06.10. 조이스틱 + 조이스틱 카메라 회전 / Euler, Mathf.Clamp (0) | 2020.06.11 |
2020.06.09. 조이스틱 구현하기 / 조이스틱 방향으로 캐릭터 회전 (0) | 2020.06.09 |