Bolt 106 - 애니메이션

Bolt는 네트워크를 통한 애니메이션 복제 메카니즘이 내장되어 있습니다. 이 챕터에서는 네트워크상에서 애니메이션을 적절하게 수행할 수 있는지에 대해서 상세하게 살펴보겠습니다.

먼저 모델과 애니메이션이 포함되어 있는 패키지를 다운로드 합니다. Unity 에셋 스토어에 있는 'Stealth' 샘플에서 가져온 것 입니다. 원하시면 에셋 스토어에서 'Stealth' 패키지를 다운로드 하여 캐릭터를 직접 엑스포트하거나 이 패키지를 다운로드 하세요:

이 튜토리얼을 진행하기 위해서 위의 패키지를 다운로드 했다고 가정하겠습니다. 패키지를 튜토리얼 프로젝트에 임포트 해주세요.

'Tutorial/Robot/Done/DonePrefabs' 폴더에서 'char_robotGuard' 프리팹을 찾아 'Tutorial/Prefabs' 폴더로 드래그하여 'Robot' 으로 이름을 변경해줍니다.

'Bolt Assets' 윈도우를 열고 새로운 상태를 생성하여 'RobotState' 로 이름을 부여합니다. 이 상태를 생성하여 이름을 부여했으면 상태 자체에서 'Import Mecanim Parameters' 설정을 찾아보세요.

'Tutorial/Robot/DoneAnimations/DoneEnemyAnimator' 에 있는 Robot의 메카님 컨트롤러를 슬롯에 드래그합니다.

'Import' 버튼을 클릭합니다.

Bolt 는 자동적으로 메카님 컨트롤러에 있는 모든 파라미터들을 상태로 임포트 합니다.

애니메이션 컨트롤로에서 파라미터를 임포트 후에 'Mecanim (State Wide)' 이라고 하는 상태에 새로운 설정이 팝업됩니다. 이것은 애니메이터 값을 변경하기 위해 animator.SetFloatanimator.SetBool 과 같은 일반적인 메카니즘 메소드를 사용하기 원하거나 대신 Bolt 상태 속성들을 사용하기 원할 때 제어할 수 있도록 해 줍니다.

이미 존재하고 애니메이션 컨트롤로상의 설정 파라미터의 표준 메카님 방식을 사용하고 있는 게임에 Bolt를 추가하고 있다면 디폴트인 'Using Animator Methods' 설정으로 두는 것이 가장 좋습니다. Bolt로 새로운 게임을 작성중이면 일반적으로 여기에서 사용할 'Using Bolt Properties' 옵션을 사용해야 합니다.

임포트를 하여 모든 파라미터들이 추가되었고 'Using Bolt Properties' 로 변경되었음을 볼 수 있으며, 또한 값들의 메카니즘 감폭 시간(damping time)을 제어하는 추가적인 옵션을 얻었습니다. 원하면 Bolt를 'Mixed Mode' 로 실행할 수 있는데 여기에선는 일부 속성들이 'Using Animator Methods' 로 설정되고 일부는 'Using Bolt Properties' 로 설정됩니다. 일반적으로 혼란스러울 수 있으므로 이렇게 하는 것은 지양하라고 권고해드립니다.

마지막으로 해야할 일은 'RobotState' 에 'Transform' 프로퍼티를 추가하는 것으로, 전에 'CubeState' 에 했던 것과 동일합니다.

  1. 상단에서 'New Property' 를 클릭합니다
  2. 생성된 프로퍼티 이름을 'Transform' 으로 변경합니다
  3. 프로퍼티 타입을 'Transform' 으로 설정합니다
  4. 'Interpolation' 을 'Smoothing Algorithm' 으로 설정합니다.

계속 진행하기전에 메카니즘 파라미터들에 대해 일부 환경 설정을 해주어야 합니다. 우선 'Shot' 과 'AimWeight' 에 대한 네트워크 복제를 사용하지 않도록 합니다. 왜냐하면 이러한 것들은 직접적으로 사용자가 제어하는 것이 아니라 애니메이션 내부의 커브들에 의해 제어되기 때문입니다. 예제에서는 이러한 파라미터들을 실제로 사용하지 않지만, 사용불가로 하지 않으면 메카님은 Bolt가 설정하려고 할 때 잘못되었다고 지적하게 됩니다.

사용할 수 없게 하는 방법은 두가지가 있습니다. 가장 쉬운 것은 제거하는 것 입니다. 다른 방법은 'Mecanim' 설정에서 'Using Animator Methods' 로 변경하고 'Replication' 을 'Local' 로 설정해주는 것 입니다. 이 뜻은 Bolt가 커브에서 값을 읽어 프로퍼티내에 값을 노출하게 하는 것이지만, 네트워크 상으로는 아무것도 전송하지 않을 것 입니다.

두 번째로 설정할 옵션은 'Speed' 의 'Damping Time' 과 'AngularSpeed' 프로퍼티로, 두 값 모드 0.1 로 설정합니다.

중요: 로봇 캐릭터에 대한 상태를 완료했습니다. 계속 진행하기 전에 Bolt를 컴파일 해주세요.

이제 'Robot' 프리팹을 Bolt 엔티티로 설정할 시간입니다. 'Tutorial/Prefabs' 폴더내의 프리팹을 선택하여 프리팹에 'Bolt Entity' 컴포넌트를 추가해주세요.

'Bolt Entity' 컴포넌트의 'State' 설정을 'IRobotState' 로 변경하고 'Robot' 프리팹을 선택하기 위해 Bolt를 다시 컴파일합니다.

세계내에서 로봇 스포닝을 시도하기 전에, Bolt에게 우리의 새로운 'Robot' 프리팹을 이전의 'Cube' 대신 인스턴스 생성해야 된다고 알려줄 필요가 있습니다. NetworkCallbacks 스크립트에서 BoltNetwork.Instantiate 호출을 BoltPrefabs.Robot 레퍼런스로 변경하여 처리합니다.

  public override void SceneLoadLocalDone(string map) {
    // randomize a position
    var pos = new Vector3(Random.Range(-16, 16), 0, Random.Range(0, 16));

    // instantiate cube
    BoltNetwork.Instantiate(BoltPrefabs.Robot, pos, Quaternion.identity);
  }

게임을 빌드하고 두개의 인스턴스를 시작하면 아래와 같이 보여야 합니다. Bolt를 사용하기 위한 'Animator' 를 아직 올바르게 할당해주지 않았기 때문에 Bolt는 에러를 리포트 해줄것입니다.

Robot(Clone)의 상태에 메카님 애니메이터를 지정하지 않았으나, 메카님을 사용하기 위한 속성들을 가지고 있습니다.

'Tutorial/Scripts' 폴더에 RobotBehaviour 스크립트를 생성하고 CubeBehaviour 에서 했던 것과 같이 디폴트 Unity 메소드를 제거하고 클래스를 Bolt.EntityBehaviour<T> 에서 상속받도록 합니다.

using UnityEngine;
using System.Collections;

public class RobotBehaviour : Bolt.EntityBehaviour<IRobotState> {

}

이제 Attached 메소드를 오버라이드하여 'Transform' 속성을 설정하고 Bolt가 사용할 상태에 애니메이터를 지정해줍니다. 트랜스폼은 전에 CubeTransform 속성에 했던 것과 같이 state.Transform.SetTransforms(transform) 로 지정해줍니다. 애니메이터는 state.SetAnimator 를 호출하여 지정하고 프리팹으로 부터 기존의 Animator 컴포넌트안으로 전달합니다.

'root motion' 이 소유자인 경우에만 사용되어진다는 것을 확인하고 싶습니다. 왜냐하면 그렇지 않으면 모션은 엔티티를 보는 모든 원격 피어들에게 이중으로 적용되어지게 되기 때문입니다. 간단히 entity.isOwnerstate.Animator.applyRootMotion 속성으로 지정합니다.

using UnityEngine;
using System.Collections;

public class RobotBehaviour : Bolt.EntityBehaviour<IRobotState> {
  public override void Attached() {
    state.Transform.SetTransforms(transform);
    state.SetAnimator(GetComponent<Animator>());

    state.Animator.applyRootMotion = entity.isOwner;
  }
}

RobotBehaviour 컴포넌트에는 방금 생성한 실제 'Robot' 프리팹이 필요합니다.

빌드하고 게임을 시작하면 로봇이 여전히 계속 서있는 것을 볼 수 있지만, 경고는 사라지게 될 것 입니다. 가장 마지막으로 해야할 일은 로봇의 이동을 제어하는 코드를 추가해주는 것 입니다. RobotBehaviour 를 다시 열고 SimulateOwner 메소드를 구현합니다. 이 메소드의 코드는 처음 볼 때는 복잡해 보이지만, 매우 간단합니다.

  1. W 가 눌렸을 때, 속도를 증가시킵니다 (방향 +1.5)
  2. W 가 눌렸을때, 속도를 앞으로 0으로 감소시킵니다
  3. A 가 눌렸을 때, 각 속도를 음수로 변경합니다 (방향 -1)
  4. D 가 눌렸을 때, 각 속도를 양수로 변경합니다 (방향 +1)
  5. A 또는 D 아무것도 눌리지 않았을 때, 각속도를 0으로 움직입니다.
  public override void SimulateOwner() {
    var speed = state.Speed;
    var angularSpeed = state.AngularSpeed;

    if (Input.GetKey(KeyCode.W)) {
      speed += 0.025f;
    }
    else {
      speed -= 0.025f;
    }

    if (Input.GetKey(KeyCode.A)) {
      angularSpeed -= 0.025f;
    }
    else if (Input.GetKey(KeyCode.D)) {
      angularSpeed += 0.025f;
    }
    else {
      if (angularSpeed < 0) {
        angularSpeed += 0.025f;
        angularSpeed = Mathf.Clamp(angularSpeed, -1f, 0);
      }
      else if (angularSpeed > 0) {
        angularSpeed -= 0.025f;
        angularSpeed = Mathf.Clamp(angularSpeed, 0, +1f);
      }
    }

    state.Speed = Mathf.Clamp(speed, 0f, 1.5f);
    state.AngularSpeed = Mathf.Clamp(angularSpeed, -1f, +1f);
  }

메소드의 시작부분에서 state.Speedstate.AngularSpeed 를 읽고 두 개의 로컬 변수에 저장합니다. 작업이 쉽기 때문에 이렇게 진행합니다. 메소드의 마지막 부분에서는 state에 0.0과 1.5f 사이의 speed 를 Clamp 하고 angularSpeed 를 -1과 +1 간의 Clamp를 해 되돌아 갑니다.

게임을 다시 빌드하면 WAD 키를 사용하여 로봇 캐릭터가 주위를 걷게 할 수 있습니다. 아래는 유튜브에 있는 결과 동영상입니다.

기술문서 TOP으로 돌아가기