Unity 3D animation.MatchTarget с корневым движением, затрагивающим только положение или только вращение

Фон

В движке Unity 3D версии 2017.3.1f1 я работаю над трехмерным персонажем, управляемым движением корневого механизма mecanim. Мне нужно повернуть персонажа точно на 180° вокруг оси Y (вверх), чтобы он затем шел влево или вправо (это 2D игра). Поскольку это mecanim, углы не всегда точны и персонаж поворачивается иногда на 177°, иногда на 181°. Это нежелательная ошибка, приводящая к перемещению персонажа по оси Z во время ходьбы. Поэтому я решил исправить последний угол с помощью встроенной функции animator.MatchTarget() ( https://docs.unity3d.com/ScriptReference/Animator.MatchTarget.html).

проблема

Animator.MatchTarget не имеет перегруженной функции для соответствия только повороту, поэтому мне нужно ввести конечную позицию анимационного ролика поворота (анимация поворота имеет движение корня и изменение положения). Я предположил, что переменная-член Animator.TargetPositon делает работу:

// following script is attached to the character rotation Animator state
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenericState : StateMachineBehaviour {

     public float targetAngle_ = 180.0f;

     override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){

         Quaternion targetRotation_ = Quaternion.Euler(0, targetAngle_, 0); 
         animator.MatchTarget(animator.targetPosition, 
                              targetRotation_, 
                              AvatarTarget.Root, 
                              new MatchTargetWeightMask(Vector3.one, 1f),
                              0f,
                              1f);
     }
}

Но это не связано с движением корня, поэтому персонаж заканчивается в той же позиции, в которой он начал анимацию хода. Есть еще одна переменная Animator.RootPosition ( https://docs.unity3d.com/ScriptReference/Animator-rootPosition.html), но она просто содержит текущую позицию символа.

Временное решение

Единственное решение, которое я могу придумать, - это прочитать данные анимации в режиме редактора, сохранить смещение корневого движения, а затем применить для каждой анимации во время выполнения. Это решение слишком сложное, и я ищу простую альтернативу "сопоставить просто вращение и прочитать положение цели из корневого движения в анимации".

Спасибо

1 ответ

Работает следующий обходной путь (без доступа к анимационным кривым в режиме редактирования). Обратите внимание, что OnStateMove используется вместо OnStateUpdate. Когда OnStateMove переопределяется, корневое движение игнорируется в состоянии и должно применяться вручную ( https://docs.unity3d.com/ScriptReference/Animator.ApplyBuiltinRootMotion.html) в этом методе. Каким-то образом это работает лучше, чем Animator.MatchTarget()

// following script is attached to the character rotation Animator state
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GenericState : StateMachineBehaviour {

    public bool _SnapEnabled;

    Quaternion _enterRotation;
    public float targetAngle_ = 180.0f;

    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){
        _enterRotation = animator.rootRotation;
    }

    override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){
        float normalizedTime_ = Mathf.Clamp(
                               (stateInfo.normalizedTime - _matchMin) /
                               (_matchMax - _matchMin), 0f, 1f);

        if ( _SnapEnabled && normalizedTime_ > 0 ){
            Quaternion snappedRotation_ = Quaternion.Euler(0, targetAngle_, 0);
            Quaternion targetRotation_ = Quaternion.Lerp(_enterRotation,
                                              snappedRotation_,
                                              normalizedTime_);

            animator.transform.position = animator.rootPosition;
            animator.transform.rotation = targetRotation_;
        } else {
            animator.ApplyBuiltinRootMotion();
        }
    }
}
Другие вопросы по тегам