IK动画与MatchTarget区别:
MatchTarget实现从一段时间区域内,一个点到另一个点匹配的过程;IK动画用于直接将手或脚与某点的匹配
控制策略:a、在木头下新建两个点(空的GameObject),将这两个点调到合适位置,让手与这两个点进行匹配,完成托举木头的效果;
b、在匹配过程中,手部的旋转角度和位置是根据GameObject来匹配的,我们可以通过调节GameObject的角度和位置完成动画的手部角度的调节。
运行时可暂停运行,调节位置,逐帧更新动画,Transform齿轮处可Copy Component,调节完成后取消运行动画,Paste Component Values
1、勾选动画层的IK Pass
2、Player C#补充:
OnAnimatorIK(int layerIndex)方法在Update()方法外,因为勾选了IK Pass,系统会自动调用
print(layerIndex);可在控制台输出当前调用的动画层是几
Player总代码:
using UnityEngine;
public class Player : MonoBehaviour {
private Animator anim;
private int speedRotateID = Animator.StringToHash("SpeedRotate");
private int speedZID = Animator.StringToHash("SpeedZ");
private int vaultID = Animator.StringToHash("Vault");
private Vector3 matchTarget;
private CharacterController characterController;
private int vaultCurveID = Animator.StringToHash("vaultCurve");
private int sliderID = Animator.StringToHash("Slider");
private int sliderCurveID = Animator.StringToHash("sliderCurve");
private int isHoldLogID = Animator.StringToHash("IsHoldLog");
public Transform LeftHand, RightHand;
public GameObject unityLog;
void Start () {
anim = GetComponent<Animator>();
characterController = GetComponent<CharacterController>();
}
void Update () {
anim.SetFloat(speedZID, Input.GetAxis("Vertical") * 4.5f);
anim.SetFloat(speedRotateID, Input.GetAxis("Horizontal")*126);
ProcessVault();
ProcessSlider();
}
private void ProcessVault()
{
if (anim.GetFloat(speedZID) > 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("LocalMotion"))
{
RaycastHit hit;
if (Physics.Raycast(transform.position + Vector3.up * 0.3f, transform.forward, out hit, 4.5f))
{
if (hit.collider.tag == "Obstacle")
{
if (hit.distance > 3)
{
Vector3 point = hit.point;
point.y = hit.transform.position.y + hit.collider.bounds.size.y + 0.09f; //普通的cube在水平面时默认中心高度y=0.5,但此模型水平中心高度为0(和底边一致)!,所以是它最低点位置+Y轴的大小
matchTarget = point;
anim.SetBool(vaultID, true);
}
}
}
else anim.SetBool(vaultID, false);
}
characterController.enabled = anim.GetFloat(vaultCurveID) < 0.5f;
if (anim.GetCurrentAnimatorStateInfo(0).IsName("Vault"))
{
anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.LeftHand, new MatchTargetWeightMask(Vector3.one, 0), 0.32f, 0.4f);
}
}
private void ProcessSlider()
{
if (anim.GetFloat(speedZID) > 3 && anim.GetCurrentAnimatorStateInfo(0).IsName("LocalMotion"))
{
RaycastHit hit;
if (Physics.Raycast(transform.position + Vector3.up * 1.5f, transform.forward, out hit, 5f))
{
if (hit.collider.tag == "Obstacle")
{
if (hit.distance <2.8)
{
Vector3 point = hit.point;
point.y = 0 ;
matchTarget = point+transform.forward*2;
anim.SetBool(sliderID, true);
}
}
}
}
else anim.SetBool(sliderID, false);
if (anim.GetCurrentAnimatorStateInfo(0).IsName("Slider"))
{
anim.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.Root, new MatchTargetWeightMask(new Vector3(1,0,1), 0), 0.38f, 0.67f);
}
if (anim.GetCurrentAnimatorStateInfo(0).IsName("Slider" ))
{
characterController.enabled = anim.GetFloat(sliderCurveID) < 0.5f;
}
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Log")
{
Destroy(other.gameObject);
unityLog.SetActive(true);
anim.SetBool(isHoldLogID, true);
}
}
private void OnAnimatorIK(int layerIndex)
{
if (layerIndex == 1) //动画层从0开始排序
{
//print(layerIndex);
int Weight = anim.GetBool(isHoldLogID) ? 1 : 0; //三元运算符
anim.SetIKPosition(AvatarIKGoal.LeftHand, LeftHand.position);
anim.SetIKRotation(AvatarIKGoal.LeftHand, LeftHand.rotation);
anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, Weight);
anim.SetIKRotationWeight(AvatarIKGoal.LeftHand, Weight);
anim.SetIKPosition(AvatarIKGoal.RightHand, RightHand.position);
anim.SetIKRotation(AvatarIKGoal.RightHand, RightHand.rotation);
anim.SetIKPositionWeight(AvatarIKGoal.RightHand, Weight);
anim.SetIKRotationWeight(AvatarIKGoal.RightHand, Weight);
}
}
}
动画展示:
动画系统其他各功能链接:TimeLine
大家还有什么问题,欢迎在下方留言!
如果你有 技术的问题 或 项目开发
都可以加下方联系方式
和我聊一聊你的故事🧡