Procedurally move a character

amrita

New member
Hi. What I'm trying to do is move a character "from code". To accomplish this I created an empty scene, with just a terrain and 2 character: one of them is the "standard" Nolan, the other one is the one I need to move, let's call it Joe. So I attached a script to Joe that just "copy" Nolan. The "copy" is done in the FixedUpdate method, through the DeterministicObjectManager:
C#:
void FixedUpdate()
{
    DeterministicObjectManager.SetCharacterMovementInput(
        mJoe.DeterministicObjectIndex,
        mNolanAnimatorMonitor.HorizontalMovement,
        mNolanAnimatorMonitor.ForwardMovement);
    DeterministicObjectManager.SetCharacterDeltaYawRotation(
        mJoe.DeterministicObjectIndex,
        mNolan.DeltaYawRotation);

}
To check whether Joe drift or not I added a debug line in LateUpdate() where I print Joe's actual position and expected position (X and Z).
With just this code, as I was expecting, Joe drift.
So to get rid of the drift I added

void LateUpdate()
{
DeterministicObjectManager.SetCharacterPosition(
mJoe.DeterministicObjectIndex,
Nolan.transform.position + mPositionOffset);

DeterministicObjectManager.SetCharacterRotation(
mJoe.DeterministicObjectIndex,
Nolan.transform.rotation);
}

to the LateUpdate method. This way the drift disappear and Joe is positioned exactly where I want.
The problem is that setting the position causes small glitches to Joe's animation...

So the question is: how should I do? Am I on the right way or is there a better alternative to achieve what I am trying to do (I guess using the AnimatorMonitor)?

(couldn't format the second code, because the editor didn't let me)
 
SetCharacterMovementInput and SetCharacteDeltaYawRotation should be done within Update otherwise you'll have timing issues. Anytime that you want to explicitly set the position you should create a new ability that will set the move direction, similar to what the NavMeshMovement ability does. The controller requires a pretty precise execution order in order to have the smooth results and by positioning the character within an ability you'll ensure things are in the correct order.
 
Hi, after some try I'm back here. I created a new PlayerInput, a new ILookSource and a new MovemetType, but I can't make them work. The horizontal/forward movements work fine, the problems start when I add the rotation stuff...

Just a brief explanation on what I'm trying to accomplish:
I want to "mirror" a character, so I created an data source object where the mirrored character push its position/rotation/status (aiming/crouching/abilities..). Every n milliseconds the "clone" retrieve these informations from the data source object and "go" to the retrieved position/rotation and start the required abilities.

What I did so far is create the "clone" as a AI character (without the NavMeshAgent) and add the UltimateCharacterControllerHandler script. I also added the MirrorLookSource and the MirrorInput and setted the MirrorMovementType on the UltimateCharacterController.

C#:
public class MirrorInput : PlayerInput
{
    private InputBase m_Input;

    protected override void Awake()
    {
        base.Awake();

        m_Input = Demo.GetInputDataSource(this.gameObject.GetComponent<CharacterIdObject>());
        m_Input.Initialize(this);
    }

    protected override bool GetButtonInternal(string name)
    {
        return m_Input.GetButton(name, InputBase.ButtonAction.GetButton);
    }

    protected override bool GetButtonDownInternal(string name)
    {
        return m_Input.GetButton(name, InputBase.ButtonAction.GetButtonDown);
    }

    protected override bool GetButtonUpInternal(string name)
    {
        return m_Input.GetButton(name, InputBase.ButtonAction.GetButtonUp);
    }

    protected override float GetAxisInternal(string name)
    {
        return m_Input.GetAxis(name);
    }

    protected override float GetAxisRawInternal(string name)
    {
        return m_Input.GetAxis(name);
    }
}

public class MirrorLookSource : MonoBehaviour, ILookSource
{
    private void Awake()
    {
        m_GameObject = gameObject;
        m_Transform = transform;

        m_Input = Demo.GetInputDataSource(this.gameObject.GetComponent<CharacterIdObject>());
    }

    private void OnEnable()
    {
        if (m_Started)
        {
            EventHandler.ExecuteEvent<ILookSource>(m_GameObject, "OnCharacterAttachLookSource", this);
        }
    }

    private void Start()
    {
        m_Started = true;
        EventHandler.ExecuteEvent<ILookSource>(m_GameObject, "OnCharacterAttachLookSource", this);
    }

    private void OnDisable()
    {
        EventHandler.ExecuteEvent<ILookSource>(m_GameObject, "OnCharacterAttachLookSource", null);
    }

    public Vector3 LookDirection(bool characterLookDirection)
    {
        if (m_InputSource != null && m_InputSource.HasData())
        {
            return (m_InputSource.GetActualPosition() - m_Transform.position).normalized;
        }
        return m_Transform.forward;
    }

    public Vector3 LookDirection(Vector3 lookPosition, bool characterLookDirection, int layerMask, bool useRecoil)
    {
        if (m_InputSource != null && m_InputSource.HasData())
        {
            return (m_InputSource.GetActualPosition() - lookPosition).normalized;
        }
        return m_Transform.forward;
    }

    public Vector3 LookPosition()
    {
        return m_Transform.position;
    }
}

public class MirrorMovement : Adventure
{
    public override float GetDeltaYawRotation(float characterHorizontalMovement, float characterForwardMovement, float cameraHorizontalMovement, float cameraVerticalMovement)
    {
        if (characterHorizontalMovement != 0 || characterForwardMovement != 0)
        {
            var lookRotation = Quaternion.LookRotation(m_Transform.rotation * m_LookSource.LookDirection(false));
            return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, lookRotation).eulerAngles.y);
        }
        return 0;
    }
}

The problem is that the clone start running in circles, even when the mirrored character stand still... So the question is: what am I missing?
 
Top