ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 21.03.15 - CLC 6일차: 움직이는 물체
    Devil Toast/Cat Like Coding 2021. 3. 15. 18:47

    확실히 기본부터 다시 하겠다고 마음먹은 보람은 생기는 중.

    이래저래 새롭게 알게된 사실이 정말 많다.

     

    정리는 하단에서 하기로 하고.

     

    일단 기존에 하던 Tutorial은 계속 랜더링 과정이라 탬포를 잡기 위해 조금 재미있어 보이는 다음 과로 넘어갔다.

    단원 명은 Movement이고, 21년 3월 기준으로 11개의 강의로 이루어져 있다.

     

    저번에는 매 강의마다 프로젝트를 팠는데, 너무 비효율적이라 Scene으로만 나누기로 했다.

     

    일단 1개는 어제 실행까지 했고, 다른 하나는 공부는 했는데 내일 해볼 생각이다.

    오늘은 밀린 것들 처리부터가 우선이라서.

     

    catlikecoding.com/unity/tutorials/movement/sliding-a-sphere/

     

    Sliding a Sphere

    A Unity Movement tutorial about sliding a sphere based on player input.

    catlikecoding.com

    아주 단순해보이는 강의지만 컴포넌트에 과도하게 의존하기 않고 코드상에서 많은 걸 해결하고 있다.

    Physics 없이 가속도나 바운드를 구현하고 있다.

     

    일단 결과물부터 올리고

     

    (1) Trail Component

    물체가 움직일 때 뒤에 trail이 나타나도록 하는 컴포넌트.

    디버깅과는 달라서 인게임에서도 드러난다.

     

    다만 이 튜토리얼을 그대로 하면 trail에 쓰려고 만든 붉은 material이 적용되지 않는 걸 볼 수 있는데,

    해당 Material의 Shader 옵션을 Particles / Standard Unlit으로 바꾸면 된다.

     

    Material이나 Sprite 등에서 이런 식으로 적용이 안되는 경우가 있는데, 구글링하면 다 해결된다.

    (어디서 봤는데, 깜빡하고 링크를 안 적어둬서 모르겠다. 좀 오랫동안 해맨 문제라서...)

     

    Material의 inspector 창에 있다

    (2) 3D 세상에서 Vector2 쓰기

    Unity에서 y축은 보통 위를 의미한다. 그래서 나도 보통은 그냥 Vector3 성분을 쓰고, 점프할 게 아니고선 y성분을 특정 상수로 고정시켜서 사용하는데, 여기는 좀 달랐다.

     

    물체의 움직임을 WASD로 하고 Horizontal / Vertical 값을 Input. GetAxis( )로 받는 것도 동일한데,

    이 값을 Vector2형인 playerInput으로 받는다.

     

    이 예제는 탑뷰에서 이루어지고 점프는 고려하지 않기 때문에 월드 좌표 상 y값에 영향을 줄 이유가 없다는 걸 알고 있고, 그렇기 때문에 굳이 이를 0f로 둘 것 없이 고려 대상에서 배제시킨 것.

     

    Vector2 playerInput;

    playerInput.x = Input. GetAxis("Horizontal");

    playerInput.y = Input. GetAxis("Vertical);

     

    이러면 물체가 y값이 바뀌면서 위로 가는 거 아닌가 걱정이 될 수도 있는데, 여기서 받은 y성분은 나중에 Vector3에서 z 성분에 넣어준다. 이런 식으로.

     

    Vector3 acceleration = new Vector3 (playerInput.x, 0f, playerInput.y) * maxSpeed;

     

    굳이 필요없는 한 성분이 존재하는 3D라면 고려해볼만한 요소일수도.

     

    (3) 새로운 라이브러리 메소드

    - Vector3. Clamp Magnitude

    docs.unity3d.com/ScriptReference/Vector3.ClampMagnitude.html

     

    public static Vector3 ClampMagnitude (Vector3 vector, float maxLength)

     

    보통 벡터의 방향성분을 쓰려면 Normalize( )를 사용하지만, 이 경우 크기가 무조건 1이 된다는 문제점이 생긴다.

    즉 1보다 작은 크기의 힘이 왔을 때 그 점점 늘어나는 규모를 적용할 수 없게 된다.

     

    이 메소드의 경우, float형 maxLength보다 큰 경우 maxLength로 vector의 크기를 바꿔서 리턴하지만, 만약 제한보다 작다면 그대로 리턴하게 된다. 즉, 상한 제한 메소드인 것.

     

    - Mathf. Move Towards

    docs.unity3d.com/ScriptReference/Mathf.MoveTowards.html

     

    public static float MoveTowards(float current, float target, float maxDelta)

     

    current값에서 target 값으로 이동시킨 후 그 값을 리턴한다. 다만 둘 사이의 차이가 max Delta보다 크다면 이를 넘지 못하고 최대한 이동한 만큼의 값을 리턴한다.

     

    속도나 가속도에 상한선을 정해둘 경우, 만약 넘지 않을때 무조건 더하도록 하면 상한을 넘는 over shooot가 발생할 수 있다. 그렇다고 매번 over shoot까지 검사하기는 코드가 지저분할 수 있다.

    그래서 더하기는 더하되 상한선을 넘지 않도록 하는 이 메소드를 사용하는 것이다.

     

    cf. 기능은 비슷하지만 float 실수값 대신 Vector3에 대해 적용되는 Vector3. MoveTowards( )가 별도로 있으니 네임 스페이스로 명시할 때 주의.

     

    - Mathf. Clamp

    docs.unity3d.com/ScriptReference/Mathf.Clamp.html

     

    public static float Clamp(float value, float min, float max)

     

    이것도 꽤 편리한데, 최대값과 최소값 사이를 동시에 검사하는 용도. 이 프로젝트에서는 Rect를 정의하고 그 제한선을 벗어나지 못하도록 하는데, 매번 if문으로 최대 최소 각각 검사하기가 번거롭다. (게다가 결국 하는 동작은 똑같으니까)

     

    그래서 value의 값이 min보다 작으면 min으로, max보다 크면 max로 보내버린다.

    이게 단 한줄에 되다니!

     

    (4) 제자리에서 물체를 조이스틱처럼 움직이기

    이건 의도했다기 보다는.. 보통 조이스틱이라고 하면 고정된 위치에서 이동값이 제한된 물체를 의미하는데, 그냥 if문으로 묶거나 강제로 초기화시킬 것 없이 그냥 이동이 +=이라는 것만 이해하면, 단순히 = 대입으로 처리하면 어차피 상한이 생기는 게 아닌가 생각이 들었다.

     

    (5) 변위/속도/가속도에 대한 이해

    이 예제는 처음에는 단순히 번위만 넣었다가, 후에 velocity, acceleration을 차차 코드에 추가하게 된다.

     

    가령,

     

    Vector3 displacement = new Vecotr3(playerInput.x, 0f, playerInput.y);

    transform. localPosition += displacement;

     

    이 경우 time.deltaTime이 없기 때문에 물체가 한 번에 너무 많이 움직여서 컨트롤이 어렵게 된다.

    물론 그냥 time. deltaTime을 곱하면 끝나는 문제이기는 하다.

     

    Vector3 displacement = new Vector3(playerInput.x, 0f, playerInput.z);

    displacement *= Time.deltaTime;

    transform. localPosition += displacement;

     

    그런데 그렇게 되면 우리는 '변위 * 시간'의 값을 다시 '변위'에 대입하는 꼴이 된다. 물리적으로 봤을 때 당연히 말이 안되는 도식이다.

     

    그래서, velocity를 넣어서 이 넌센스를 제거하는 것.

     

    Vector3 velocity = new Vector3(playerInput.x, 0f, playerInput.y);

    Vector3 displacement = velocity * Time.deltaTime;

    transform.localPosition += displacement;

     

    나중에 가속도를 쓸 때도 velocity에 time을 곱하는 게 아니라, 별도의 acceleration을 구하고 time을 곱하게 된다.

     

    (6) 참고: velocity의 위치

    이건 사람에 따라 혼동될 수도 있는데, 중간에 velocity를 쓰게 되면 velocity에서 이 값을 찾을 수 없다고 오류가 날 때가 있다.

     

    처음에는 왜인가 했는데, velocity를 Update( )의 로컬 변수로 사용했기 때문.

    2.4에서 Acceleration을 쓰게되면

     

    Vector3 acceleration = new Vector3 (playerInput.x, 0f, playerInpu.y) * maxSpeed;

    velocity += acceleration * Time. deltaTime;

     

    하게 되는데, 이 velocity를 더하는 부분에서 '찾을 수 없다'라는 오류가 뜹니다.

     

    왜냐면 예제에서는 Vector3 velocity;라고만 정의했는데, 이게 로컨 변수라면 '값이 초기화되지 않은' 매우 위험한 상태이기 때문이다.

     

    그러면 예제가 틀렸는가? 그건 아니고, 원래는 클래스의 멤버로 velocity를 사용해야 한다.

    그래서 velocity가 Update( )가 끝나도 보존이 되면서 acceleration이 축적되기 때문.

     

    그리고 값이 보존되므로 '찾을 수 없다'라는 오류도 뜨지 않는다.

     

    이걸 왜 몰랐지..

    'Devil Toast > Cat Like Coding' 카테고리의 다른 글

    21.03.24 - CLC: Orbit Camera  (0) 2021.03.25
    21.03.18 - CLC 7일차: Physics  (0) 2021.03.18
    21.03.10 - CLC 4일차 + 5일차  (0) 2021.03.10
    21.03.08 - CLC 3일차  (0) 2021.03.08
    21.03.04, CLC - 2일차  (0) 2021.03.04
Designed by Tistory.