profile image

L o a d i n g . . .

article thumbnail image
Published 2020. 9. 4. 00:18
반응형

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

 

Unity - Scripting API: Transform.eulerAngles

Transform.eulerAngles represents rotation in world space. When viewing the rotation of a GameObject in the Inspector, you may see different angle values from those stored in this property. This is because the Inspector displays local rotation, for more inf

docs.unity3d.com

 

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) 현상

youtu.be/zc8b2Jo7mno

 

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 인스턴스 옆에 화살표 눌러도 수정 모드로 갈 수 있다. 오토 세이브 가능! 

반응형
복사했습니다!