Unity 自动寻路Navmesh之跳跃,攀爬,斜坡

在之前的几篇Blog总,我们已经系统学习了自动寻路插件Navmesh的相关概念和细节。然而,如果要做一个场景精美的手游,需要用到各种复杂的场景地形,而不仅仅是平地上的自动寻路。今天我们将通过一个完整的复杂的实例,来贯穿各个细节。我们将实现一个复杂的场景,角色可以在里面攀爬,跳跃,爬坡。是不是感觉很像当年的CS游戏呢?本案例将会用得一些基本的动画函数,大家可以先结合文档有个大概的了解。本实例是在官方的范例上加工而成。

(转载请注明原文地址http://blog.csdn.net/janeky/article/details/17598113)

  • 步骤
1.在场景中摆放各种模型,包括地板,斜坡,山体,扶梯等
2.为所有的模型加上Navigation Static和OffMeshLink Generatic(这个根据需要,例如地板与斜坡相连,斜坡就不需要添加OffMeshLink)
3.特殊处理扶梯,需要手动添加Off Mesh Link,设置好开始点和结束点
4.保存场景,烘焙场景
5.添加角色模型,为其加Nav Mesh Agent组件

6.为角色添加一个新脚本,AgentLocomotion.cs,用来处理自动寻路,已经角色动画变换。代码比较长,大家可以结合注释来理解

using UnityEngine;
using System.Collections;public class AgentLocomotion : MonoBehaviour
{private Vector3 target;//目标位置private NavMeshAgent agent;private Animation anim;//动画private string locoState = "Locomotion_Stand";private Vector3 linkStart;//OffMeshLink的开始点private Vector3 linkEnd;//OffMeshLink的结束点private Quaternion linkRotate;//OffMeshLink的旋转private bool begin;//是否开始寻路// Use this for initializationvoid Start(){agent = GetComponent();//自动移动并关闭OffMeshLinks,即在两个隔离障碍物直接生成的OffMeshLink,agent不会自动越过agent.autoTraverseOffMeshLink = false;//创建动画AnimationSetup();//起一个协程,处理动画状态机StartCoroutine(AnimationStateMachine());}void Update(){//鼠标左键点击if (Input.GetMouseButtonDown(0)){//摄像机到点击位置的的射线Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){//判断点击的是否地形if (hit.collider.tag.Equals("Obstacle")){begin = true;//点击位置坐标target = hit.point;}}}//每一帧,设置目标点if (begin){agent.SetDestination(target);}}IEnumerator AnimationStateMachine(){//根据locoState不同的状态来处理,调用相关的函数while (Application.isPlaying){yield return StartCoroutine(locoState);}}//站立IEnumerator Locomotion_Stand(){do{UpdateAnimationBlend();yield return new WaitForSeconds(0);} while (agent.remainingDistance == 0);//未到达目标点,转到下一个状态Locomotion_MovelocoState = "Locomotion_Move";yield return null;}IEnumerator Locomotion_Move(){do{UpdateAnimationBlend();yield return new WaitForSeconds(0);//角色处于OffMeshLink,根据不同的地点,选择不同动画if (agent.isOnOffMeshLink){locoState = SelectLinkAnimation();return (true);}} while (agent.remainingDistance != 0);//已经到达目标点,状态转为StandlocoState = "Locomotion_Stand";yield return null;}IEnumerator Locomotion_Jump(){//播放跳跃动画string linkAnim = "RunJump";Vector3 posStart = transform.position;agent.Stop(true);anim.CrossFade(linkAnim, 0.1f, PlayMode.StopAll);transform.rotation = linkRotate;do{//计算新的位置float tlerp = anim[linkAnim].normalizedTime;Vector3 newPos = Vector3.Lerp(posStart, linkEnd, tlerp);newPos.y += 0.4f * Mathf.Sin(3.14159f * tlerp);transform.position = newPos;yield return new WaitForSeconds(0);} while (anim[linkAnim].normalizedTime < 1);//动画恢复到Idleanim.Play("Idle");agent.CompleteOffMeshLink();agent.Resume();//下一个状态为Standtransform.position = linkEnd;locoState = "Locomotion_Stand";yield return null;}//梯子IEnumerator Locomotion_Ladder(){//梯子的中心位置Vector3 linkCenter = (linkStart + linkEnd) * 0.5f;string linkAnim;//判断是在梯子上还是梯子下if (transform.position.y > linkCenter.y)linkAnim = "Ladder Down";elselinkAnim = "Ladder Up";agent.Stop(true);Quaternion startRot = transform.rotation;Vector3 startPos = transform.position;float blendTime = 0.2f;float tblend = 0f;//角色的位置插值变化(0.2内变化)do{transform.position = Vector3.Lerp(startPos, linkStart, tblend / blendTime);transform.rotation = Quaternion.Lerp(startRot, linkRotate, tblend / blendTime);yield return new WaitForSeconds(0);tblend += Time.deltaTime;} while (tblend < blendTime);//设置位置transform.position = linkStart;//播放动画anim.CrossFade(linkAnim, 0.1f, PlayMode.StopAll);agent.ActivateCurrentOffMeshLink(false);//等待动画结束do{yield return new WaitForSeconds(0);} while (anim[linkAnim].normalizedTime < 1);agent.ActivateCurrentOffMeshLink(true);//恢复Idle状态anim.Play("Idle");transform.position = linkEnd;agent.CompleteOffMeshLink();agent.Resume();//下一个状态StandlocoState = "Locomotion_Stand";yield return null;}private string SelectLinkAnimation(){//获得当前的OffMeshLink数据OffMeshLinkData link = agent.currentOffMeshLinkData;//计算角色当前是在link的开始点还是结束点(因为OffMeshLink是双向的)float distS = (transform.position - link.startPos).magnitude;float distE = (transform.position - link.endPos).magnitude;if (distS < distE){linkStart = link.startPos;linkEnd = link.endPos;}else{linkStart = link.endPos;linkEnd = link.startPos;}//OffMeshLink的方向Vector3 alignDir = linkEnd - linkStart;//忽略y轴alignDir.y = 0;//计算旋转角度linkRotate = Quaternion.LookRotation(alignDir);//判断OffMeshLink是手动的(楼梯)还是自动生成的(跳跃)if (link.linkType == OffMeshLinkType.LinkTypeManual){return ("Locomotion_Ladder");}else{return ("Locomotion_Jump");}}private void AnimationSetup(){anim = GetComponent();// 把walk和run动画放到同一层,然后同步他们的速度。anim["Walk"].layer = 1;anim["Run"].layer = 1;anim.SyncLayer(1);//设置“跳跃”,“爬楼梯”,“下楼梯”的动画模式和速度anim["RunJump"].wrapMode = WrapMode.ClampForever;anim["RunJump"].speed = 2;anim["Ladder Up"].wrapMode = WrapMode.ClampForever;anim["Ladder Up"].speed = 2;anim["Ladder Down"].wrapMode = WrapMode.ClampForever;anim["Ladder Down"].speed = 2;//初始化动画状态为Idleanim.CrossFade("Idle", 0.1f, PlayMode.StopAll);}//更新动画融合private void UpdateAnimationBlend(){//行走速度float walkAnimationSpeed = 1.5f;//奔跑速度float runAnimationSpeed = 4.0f;//速度阀值(idle和walk的临界点)float speedThreshold = 0.1f;//速度,只考虑x和zVector3 velocityXZ = new Vector3(agent.velocity.x, 0.0f, agent.velocity.z);//速度值float speed = velocityXZ.magnitude;//设置Run动画的速度anim["Run"].speed = speed / runAnimationSpeed;//设置Walk动画的速度anim["Walk"].speed = speed / walkAnimationSpeed;//根据agent的速度大小,确定animation的播放状态if (speed > (walkAnimationSpeed + runAnimationSpeed) / 2){anim.CrossFade("Run");}else if (speed > speedThreshold){anim.CrossFade("Walk");}else{anim.CrossFade("Idle", 0.1f, PlayMode.StopAll);}}
}


效果图如下,点击任何一个地点,角色都可以自动寻路过去。中间可能经过不同的障碍物,我们可以看到角色如我们所预料的一样,可以跳跃下来,可以爬楼梯,最终到达目标点。


  • 总结

今天的这个例子比较复杂,要根据寻路网格的类型,来处理角色的动作是普通寻路,还是攀爬,抑或跳跃。这个例子应该是比较接近真实项目了。大家在实际项目中如果还有更加复杂的寻路,欢迎探讨。ken@iamcoding.com

  • 源码

http://pan.baidu.com/s/1i35cVOD

  • 参考资料
1.http://www.xuanyusong.com/
2.http://liweizhaolili.blog.163.com/
3.http://game.ceeger.com/Components/class-NavMeshAgent.html

转载于:https://www.cnblogs.com/nafio/p/9137251.html


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部