Rotation
Do not set one of the eulerAngles axis separately (eg. eulerAngles.x = 10; ) since this will lead to drift and undesired rotations. When setting them to a new value set them all at once as shown above.
eulerAngles 축 중 하나를 별도로 설정하지 마라. (예: eulerAngles.x = 10;) 이는 표류(drift) 및 원치 않는 회전을 유발한다. 새 값으로 설정할 때는 모두 한꺼번에 설정하라. (예: transform.eulerAngles = new Vector3(0.0f, 0.0f, 0.0f);)
docs.unity3d.com/ScriptReference/Transform-eulerAngles.html
float _yAngle = 0.0f;
void Update()
{
_yAngle += Time.deltaTime * 100.0f;
transform.eulerAngles = new Vector3(0.0f, _yAngle, 0.0f);
// ...
}
transform.rotation이 Quaternion 타입인 이유? 짐벌락(Gimbal Lock) 현상
Quaternion.LookRotation(): 특정 방향을 바라보게끔 한다.
Lerp/Slerp과 함께 사용하면 스르륵 움직이게끔 처리가 가능하다.
if(Input.GetKey(KeyCode.W))
{
transform.Translate(Vector3.forward * Time.deltaTime * _speed);
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), 0.2f);
}
if(Input.GetKey(KeyCode.S))
{
transform.Translate(Vector3.back * Time.deltaTime * _speed);
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.back), 0.2f);
}
if (Input.GetKey(KeyCode.A))
{
transform.Translate(Vector3.left * Time.deltaTime * _speed);
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.left), 0.2f);
}
if (Input.GetKey(KeyCode.D))
{
transform.Translate(Vector3.right * Time.deltaTime * _speed);
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), 0.2f);
}
움직임이 어색하기 때문에 position에 처리하는 방식으로 변경한다.
if(Input.GetKey(KeyCode.W))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), 0.2f);
transform.position += Vector3.forward * Time.deltaTime * _speed;
}
if(Input.GetKey(KeyCode.S))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.back), 0.2f);
transform.position += Vector3.back * Time.deltaTime * _speed;
}
if (Input.GetKey(KeyCode.A))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.left), 0.2f);
transform.position += Vector3.left * Time.deltaTime * _speed;
}
if (Input.GetKey(KeyCode.D))
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), 0.2f);
transform.position += Vector3.right * Time.deltaTime * _speed;
}
Input Manager
Update()에서 하나씩 체크해도 괜찮으나, 프로젝트 사이즈가 커질수록 성능 부하가 일어날 수 있다. => 공용으로 사용할 수 있는 매니저로 뽑는다!
Update()에 전부 넣으면 어디서 키보드 입력을 받았는지 찾기가 힘들다. 따라서 입력을 이벤트로 처리를 한다면 디버깅 시에도 매우 편리하다!
public class InputManager
{
// 일종의 delegate, listener 패턴
public Action KeyAction = null;
public void OnUpdate()
{
if (Input.anyKey == false)
return;
if (KeyAction != null)
KeyAction.Invoke(); // 키 액션 있었다고 알리기
}
}
Action == return값이 없는 함수를 참조하는 delegate
Prefab
자식 객체로 넣어 버리면 기준이 달라진다!
예를 들어 포신을 Y축 회전해야 할 때, 월드 좌표가 아닌 탱크 좌표로 기준이 잡혀 있다면 좀 더 편리할 것이다.
Prefab: 붕어빵 틀!
class Tank
{
// 각종 정보들
float speed = 10.0f;
}
만약 Tank를 다섯 개 생성한다고 가정하자. 상단 코드(각 인스턴스 접근이 아님에 주의!)에서 speed를 바꾼다면, Tank class의 전체 speed 값이 바뀌는 것이기 때문에, 이 변경사항은 모든 Tank에 적용될 것이다.
Prefab도 마찬가지다. Prefab만 건드리면 Prefab을 통해 만들어진 인스턴스들에 적용된다.
Prefab을 더블 클릭 하면 Prefab 수정 모드로 전환된다. Prefab 인스턴스 옆에 화살표 눌러도 수정 모드로 갈 수 있다. 오토 세이브 가능!