滑步处理 - 让动画脚步和移位一致

文章介绍了在Unity中如何利用ApplyRootMotion解决角色移动时动画与刚体不匹配的问题,通过设置动画属性、编写脚本控制动画状态,以及处理网络同步和转身等技术,实现角色一脚一个脚印的行走效果。
摘要由CSDN通过智能技术生成

游戏制作中,通常的做法是让动画播放跑步或者其他移动动画,然后让刚体跟着移动,这样就会出现不匹配现象,看起来角色看起来像滑冰一样。

Unity的动画本身有一个叫做ApplyRootMotion的东西,我么可以利用他让人物移动看起来一脚一个脚印的行走。

我们的制作原理就是把动画移动的位移数据获取到,然后利用这个位移信息进行移动。

动画处理

首先把要移动的动画要改成带位移的动画
请添加图片描述
我们来到动画的属性,需要修改Rig
在这里插入图片描述
下拉里选择CopyFromOtherAvatar,并且Source选择模型的Avatar。

来到Animation标签,这里是重点
在这里插入图片描述
对于行走动画,我们需要勾选LoopTime , LoopPose
RootTransformRotation和RootTransformPosition(Y)旋转我们不需要,所以直接勾选BakeIntoPose。
我们保留RootTransformPositionXZ。

其他移动的动画也是如此,待机动画因为不需要他有位移,所以idle我们全部勾选
在这里插入图片描述
设置完成后我们可以看下动画是否有问题
请添加图片描述

我们可以看到角色进行了移位,那么动画就设置完毕了。
动画控制器这里不说了,不是本文重点。

动画控制器设置

首先我们在Animator组件勾选ApplyRootMotion。
在这里插入图片描述

然后增加新的脚本,我这里命名TCharacterAnimation

	private void Awake()
    {
        animator = GetComponent<Animator>();
    }
	void OnAnimatorMove()
    {
        fixedDeltaTime += Time.deltaTime;
        fixedDeltaPosition += animator.deltaPosition;
        fixedDeltaRotation *= animator.deltaRotation;
    }

保存脚本后,我们发现Animator发生了变化。
在这里插入图片描述
表示现在是由脚本来接管了。

动画控制脚本

通过获得Input或者其他输入,赋值给inputXZ变量前后和移动

    Vector3 moveDirectionVelocity;
    public float smoothAccelerationTime = 0.2f; // The smooth acceleration of the speed of the character (using Vector3.SmoothDamp)
    public float linearAccelerationSpeed = 3f; // The linear acceleration of the speed of the character (using Vector3.MoveTowards)

	void CheckAni()
	{
		MovieMove = Vector3.SmoothDamp(MovieMove, inputXZ, ref moveDirectionVelocity, smoothAccelerationTime);
        MovieMove = Vector3.MoveTowards(MovieMove, inputXZ, Time.deltaTime * linearAccelerationSpeed);
        //Vector3 dir = MovieMove;// transform.InverseTransformDirection(MovieMove);

        animator.SetFloat("velocity_X", MovieMove.x);
        animator.SetFloat("velocity_Z", MovieMove.z);
    }

这里的SmoothDamp,MoveTowards是一个让输入的数据进行渐变过渡,当然你可以直接把inputXZ传入动画。有过渡会丝滑一些。
动画参数velocity_X和Z是左右移动和前后移动。

玩家控制器脚本

这个脚本就是核心了,我们需要获取到动画数据进行移动

void FixedUpdate()
{
			nowVelocity = charAnimation.fixedDeltaTime > 0f ? charAnimation.fixedDeltaPosition / charAnimation.fixedDeltaTime : Vector3.zero;
            charAnimation.fixedDeltaTime = 0f;
        	charAnimation.fixedDeltaPosition = Vector3.Zero;

            
            rig.velocity = nowVelocity;
}
            

网络同步

如果需要网络同步,我没有找到找到参考办法,我是这样处理的。
同步玩家的Input操作x和z的值。在进行处理,会出现一定的跟不上,我补充了位置同步,做一个位置慢慢的跟上的操作来弥补位置偏移。

		inputDir.x = hero.player.recInput.x;
        inputDir.z = hero.player.recInput.y;
        animator.SetFloat("velocity_X", inputDir.x);
        animator.SetFloat("velocity_Z", inputDir.z);
		float movSpeed = MoveSpeed * Time.deltaTime;
        thirdToPos = charAnimation.fixedDeltaPosition;// 
        charAnimation.fixedDeltaTime = 0f;
        charAnimation.fixedDeltaPosition = Vector3.Zero;
        
        //movePos是同步过来的位置数据
        movePos += thirdToPos; 
        //位置慢慢的跟上的操作来弥补位置偏移
        //这里需要调整速度,不能太快了
        transform.position = Vector3.Lerp(transform.position, movePos, movSpeed * 1.5f);

转身

对于转身,可以在Idle增加Turn属性来
在这里插入图片描述
转身需要勾选Position(Y)改为Feet,还有Position XZ
在这里插入图片描述
转身角度计算可以通过头部和身体的角度计算,超过一定数值,开启转身

	public float GetAngleFromForward(Vector3 worldDirection)
    {
        Vector3 local = transform.InverseTransformDirection(worldDirection);
        return Mathf.Atan2(local.x, local.z) * Mathf.Rad2Deg;
    }
    
	float angle = GetAngleFromForward(hero.refParm.headDriect_actor.forward);
	float nowTurn = Mathf.Lerp(animator.GetFloat("Turn"), angle / turnAngle, Time.deltaTime * turnSpeed);
    animator.SetFloat("Turn", nowTurn);

到这里就按脚步移动就结束了。
另外还有一些其他技术例如motion matching。

这里有一些参考:
视频教程
好用的插件 FinialIK,这里有个下载,商用请支持Z版

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值