【unity实战】实现TPS第三人称射击游戏武器灵动、自然的瞄准效果(IK | Animation Rigging | TPS)
本文介绍了如何使用Unity的Animation Rigging系统改进TPS射击游戏中人物瞄准的生硬问题。通过创建Rig并添加多目标约束(Multi-Aim Constraint),实现了头部、右手和身体的自然瞄准动作。文章详细展示了如何限制头部偏转角度(-60~60度)、调整身体旋转权重(0.7)、使用双骨骼IK约束(TwoBoneIKConstraint)让左手握枪,以及通过代码控制瞄准状态
前言
之前我做过一个TPS第三人称射击游戏项目,但是人物瞄准非常生硬:
我们可以使用Animation Rigging让它更加灵活。Animation Rigging的基础使用参考:【unity组件介绍】创建程序化动画,灵活地调整角色动作——Animation Rigging的使用
显示骨骼


实现角色的头部始终注视某个目标
创建一个rig
选中角色,点击菜单的Rig Setup按钮
这会在角色下新增一个RigBuilder组件,它会和animator组件一起来管理这个角色上的所有Rig,并在角色层下创建一个新子对象,挂载了Rig组件。
添加约束
在Rig下方创建一个新的空对象,并把此对象重命名为HeadAim。我将继续在这里添加一个Multi-Aim Constraint多目标约束组件。
受约束的对象配置为头部,Aim Axis、Up Axis是头部局部位置的前面和上面轴。配置配置Source Objects为我们要瞄准的目标对象
效果,头就跟着看向目标
限制头部偏转角度
目前人物头部可以偏转很大的角度
我们需要限制头部偏转角度,这里我配置为-60~60度
效果
右手瞄准目标
添加新的Multi-Aim Constraint多目标约束组件子物体。受约束的对象配置为右手手腕骨骼,其他配置和前面一样。
效果,右手跟着瞄准目标了
身体跟随旋转
添加新的Multi-Aim Constraint多目标约束组件子物体,受约束的对象配置为脊椎骨骼,其他配置和前面一样。
效果
但是可以发现,这样旋转导致右手的瞄准出现了问题。我们应该先旋转身体,再旋转手,修改排序,身体在前面就可以了。
效果,现在正常了
目前我觉得身体旋转过多,我们限制一下,身体权重限制在0.7左右
现在身体基本上仍然在旋转,但旋转的幅度没有那么大,这让它看起来更自然一些。
左手握枪
左手应该握住枪,添加一个TwoBoneIKConstraint双骨骼IK约束,这是用于放置手臂或腿部的东西,因此他需要两个骨骼,例如上臂和下臂,然后为尖端选择一个目标,也就是手掌。它可以用于放置手并将上臂的手臂旋转到合理的位置
我们先放入左手顶点骨骼
右键,点击Auto Setup from Tip Transform按钮
unity会自动帮我们自动选择肩膀中的肘部,并会自动创建两个对象
将这两个对象移动到右手手掌骨骼下,作为他的子物体
这里分享一个简单的快捷的方式
我们先关闭所有的骨骼IK重定向效果
运行游戏状态下,播放瞄准动画,先选中LeftHandAim_target,再选中左手手掌节点(注意选择顺序不要错),点击Align Transform按钮,同步位置
然后复制组件值,结束运行再粘贴回组件值
然后和前面一样,再运行游戏状态下,播放瞄准动画,选中LeftHandAim_hint和左手肘部节点,点击Align Transform按钮,同步位置,然后复制粘贴组件值
最后再打开Rig
效果,如果不满意效果可以在运行状态下手动微调,在复制粘贴值
更精细的限制角度



如果发现角度偏移没有达到自己设定的角度怎么办?可以配置Avatar骨骼角度限制,具体可以参考:【零基础入门unity游戏开发——unity3D篇】3D模型 —— Rig操纵页签和Avatar化身系统
代码控制
瞄准和非瞄准状态切换,默认状态不启动瞄准骨骼
[SerializeField] private Rig aimRig;//瞄准骨骼
private float aimRigWeight;//瞄准骨骼权重
//瞄准
if (inputController.isAim && isWeapon)
{
animator.SetBool(IsAiming, true);
aimRigWeight = 1f;
}
else
{
animator.SetBool(IsAiming, false);
aimRigWeight = 0f;
}
进行鼠标检测,将目标对象投射到碰撞的点上
//剔除层级
public LayerMask cullLayerMask;
//射线检测
void SetAimTarget()
{
TryGetMouseHitInfo(out var hitInfo, ~cullLayerMask);
aimTarget.position = hitInfo.point;
}
/// <summary>
/// 获取鼠标在3D世界中的命中信息
/// </summary>
/// <param name="hitInfo">射线命中信息</param>
/// <param name="layerMask">层级掩码(默认为所有层)</param>
/// <param name="maxDistance">最大检测距离</param>
/// <returns>是否命中物体</returns>
bool TryGetMouseHitInfo(out RaycastHit hitInfo, LayerMask? layerMask = null, float maxDistance = Mathf.Infinity)
{
hitInfo = default;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
return Physics.Raycast(ray, out hitInfo, maxDistance, layerMask ?? ~0);
}
效果
最后隐藏目标球体的渲染即可
专栏推荐
完结
好了,我是向宇,博客地址:https://xiangyu.blog.csdn.net,如果学习过程中遇到任何问题,也欢迎你评论私信找我。
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!
更多推荐




所有评论(0)