基于Animator.MatchTarget定点角色脚部位置,实现人物跳跃效果。本文章涉及人物移动控制,镜头跟随旋转控制,动画状态机,射线检测,动画匹配等功能。
一、最终效果
实现角色移动,镜头控制,动画 这里限制了高度,不过没有限制,将会是这样的!
二、关键Api
因为这次的动画需要匹配脚部最终的落点位置,我们需要用到animator的MatchTarget方法。 在unity的官方手册中有这个api的详细用法,在这里也详细介绍
MatchTarget(
Vector3 matchPosition,
Quaternion matchRotation,
AvatarTarget targetBodyPart,
MatchTargetWeightMask weightMask,
float startNormalizedTime,
[Internal.DefaultValue("1")] float targetNormalizedTime
);
三、制作demo流程
1.资源来源
全部都是AssetStore上的免费资源,可以选择需要的模型和场景,自己导入。 动画是来源于https://www.mixamo.com/,这是一个可以给模型绑定动画到处的网站,非常实用。 你可以在这个网站中上传模型fbx文件,然后选择动作导出下载
2.动画导入
选择你想要的动画,然后导出fbx下载,注意要去掉皮肤,这样只会导出动画文件。 导入的fbx文件,选中里面的anim文件Ctrl+D就会拷贝一份出来,只需要这个文件即可,里面有些动作会带有位移信息,可以在anim中删除
3.动画状态机
里面涉及到人物移动和跳跃,新建的状态机Animator比较简单,配置好触发器 一些动画之间的过渡,需要把这个勾去掉,这样在触发状态变化的时候,可以马上切换到下一个动画,不会等待当前动画播放完成,这样可以达到马上切换的效果。
4.镜头移动
镜头移动比较简单,这里只需要在LateUpdate中更新相机的位置即可。
public class CameraControl : MonoBehaviour
{
public Transform follow;
private Vector3 camOffset = Vector3.zero;
public float mouseScrollScale = -10;
void Start()
{
camOffset = transform.position - follow.position;
}
private void Update()
{
if (Mathf.Abs(Input.GetAxis("Mouse ScrollWheel")) > 0)
{
Camera.main.fieldOfView = Camera.main.fieldOfView + Input.GetAxis("Mouse ScrollWheel") * mouseScrollScale;
}
}
private void LateUpdate()
{
var mouse_x = Input.GetAxis("Mouse X");
var mouse_y = -Input.GetAxis("Mouse Y");
if (Input.GetMouseButton(1))
{
transform.RotateAround(follow.position, Vector3.up, mouse_x * 5);
transform.RotateAround(follow.position, transform.right, mouse_y * 5);
camOffset = transform.position - follow.position;
}
transform.position = follow.position + camOffset;
}
}
5.人物移动
人物移动需要获取键盘的输入,然后在每帧更新位置,同时更新animator的状态
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
moveDirection = camTrans.TransformDirection(moveDirection);
moveDirection.y = 0;
if (moveDirection != Vector3.zero)
{
var nextPos = transform.position + moveDirection.normalized * speed * Time.deltaTime;
transform.position = Vector3.Lerp(transform.position, nextPos, lerpDelta * Time.deltaTime);
transform.forward = Vector3.Lerp(transform.forward, moveDirection.normalized, lerpDelta * Time.deltaTime);
animator.SetBool("Run", true);
}
else
{
animator.SetBool("Run", false);
}
6.人物跳跃
在按下跳跃按钮的时候,我们需要知道前面是否有可以跳上的平台。 这里利用的射线检测,在大概小腿部的位置发出一条射线,根据检测到的目标取得平台的高度。 取得的平台高度,可以从碰撞盒的大小得出,这样就可以拿到人物最终的落脚位置
var distance = 2.0f;
var origin = transform.position + Vector3.up * 0.3f;
Physics.Raycast(origin, transform.forward, out hit, distance)
var targetSize = hit.collider.bounds.size;
matchTarget = hit.point;
matchTarget.y = targetSize.y;
最后触发跳跃动画
animator.SetTrigger(JumpStateName);
拿到匹配点后,在非过渡期间,调用MatchTarget方法
private void ProcessJump()
{
if (animator.IsInTransition(0)) return;
if (IsAnim(JumpStateName))
{
animator.MatchTarget(matchTarget, Quaternion.identity, AvatarTarget.LeftFoot, new MatchTargetWeightMask(Vector3.one, 0), 0.28f, 0.55f);
}
}
具体参数可以从动画中取得,当人物开始起跳的时间,和跳跃完成的时间,这里根据不同的动画进行微调。
四、总结
可以用这个方法,在动画播放的同时移动,然后达到目标点。同理,这个可以用来实现攀爬跨越系统。 本次案例的工程在百度云分享: 链接:https://pan.baidu.com/s/1322_yIC6f3d4V7PCyV0P6Q 提取码:3u96
最后点赞关注评论三连哦!
|