Hello there,
i have a c# script that controls the hands of my character. In the specific case, when the player is near a wall (the distance is detected with a raycast), he put his hands on that wall, in the exact point where the raycast happens.
The system works, but i’m trying now to smooth the movement of the hands, so that it looks smoother and more realistic.
Here’s the code:
using UnityEngine;
using System;
using System.Collections;
[RequireComponent(typeof(Animator))]
public class IKCtrl : MonoBehaviour
{
public Vector3 IKtarget = Vector3.zero;
protected Animator animator;
public bool ikActive = false;
void Start ()
{
animator = GetComponent<Animator>();
}
//a callback for calculating IK
void OnAnimatorIK()
{
if(animator)
{
//if the IK is active, set the position and rotation directly to the goal.
if(ikActive)
{
animator.SetIKPositionWeight(AvatarIKGoal.LeftHand,1.0f);
animator.SetIKRotationWeight(AvatarIKGoal.LeftHand,1.0f);
var handRotation = Quaternion.LookRotation(IKtarget - transform.position);
animator.SetIKRotation(AvatarIKGoal.LeftHand, handRotation);
animator.SetIKPosition(AvatarIKGoal.LeftHand,IKtarget);
}
}
}
}
How can i do that?
Since i’m a newbie, i would really appreciate specific examples.
Thanks for your help!
Matt
Edit:
Now i’m using the following function, with no results:
No, you don’t need the trick, you can use just Mathf.Lerp
public class TestIK : MonoBehaviour
{
protected Animator animator;
public bool ikActive = false;
public Transform rightHandObj = null;
public Transform lookObj = null;
float state = 0;
float elapsedTime = 0;
public float timeReaction = 0.5f;
void Start()
{
animator = GetComponent<Animator>();
state = 0;
}
// Update is called once per frame
void Update()
{
}
//a callback for calculating IK
void OnAnimatorIK()
{
if (animator)
{
//if the IK is active, set the position and rotation directly to the goal.
if (ikActive)
{
// Set the look target position, if one has been assigned
if (lookObj != null)
{
animator.SetLookAtWeight(1);
animator.SetLookAtPosition(lookObj.position);
}
// Set the right hand target position and rotation, if one has been assigned
if (rightHandObj != null)
{
//animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1f);
//animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0.5f);
if (state < 1.0f)
{
elapsedTime += Time.deltaTime;
state = Mathf.Lerp(0, 1, elapsedTime / timeReaction);
}
else
{
state = 1.0f;
elapsedTime = 0;
}
//print("elapsedTime:" + elapsedTime.ToString());
//print(state);
if (lookObj != null)
{
animator.SetLookAtWeight(state);
animator.SetLookAtPosition(lookObj.position);
}
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, state);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, state);
animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandObj.position);
animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandObj.rotation);
}
}
//if the IK is not active, set the position and rotation of the hand and head back to the original position
else
{
if (state > 0f)
{
elapsedTime += Time.deltaTime;
state = Mathf.Lerp(0, 1, elapsedTime / timeReaction);
state = 1 - state;
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, state);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, state);
animator.SetIKPosition(AvatarIKGoal.RightHand, rightHandObj.position);
animator.SetIKRotation(AvatarIKGoal.RightHand, rightHandObj.rotation);
}
else
{
state = 0;
elapsedTime = 0;
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 0);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 0);
animator.SetLookAtWeight(0);
}
}
}
}
}
i found the solution to this, it’s a bit tricky.
you must have an animation raising the hand and add a curve to it
then insteat of ikweight = mathf etc.
put
float reach = anim.GetFloat("AimWeight");
//and then
anim.SetIKPositionWeight(AvatarIKGoal.RightHand,reach);