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

转载

Unity手游之路<十>自动寻路Navmesh之跳跃,攀爬,斜坡

分类: unity
unity3dNavmesh手游自动寻路

在之前的几篇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,用来处理自动寻路,已经角色动画变换。代码比较长,大家可以结合注释来理解
[csharp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 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 initialization  void Start()  {  agent = GetComponent<NavMeshAgent>();  //自动移动并关闭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_Move  locoState = "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);  //已经到达目标点,状态转为Stand  locoState = "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);  //动画恢复到Idle  anim.Play("Idle");  agent.CompleteOffMeshLink();  agent.Resume();  //下一个状态为Stand  transform.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";  else  linkAnim = "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();  //下一个状态Stand  locoState = "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<Animation>();  // 把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;  //初始化动画状态为Idle  anim.CrossFade("Idle", 0.1f, PlayMode.StopAll);  }  //更新动画融合  private void UpdateAnimationBlend()  {  //行走速度  float walkAnimationSpeed = 1.5f;  //奔跑速度  float runAnimationSpeed = 4.0f;  //速度阀值(idle和walk的临界点)  float speedThreshold = 0.1f;  //速度,只考虑x和z  Vector3 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/lihonglin2016/p/4361162.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/574715.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

热点分析图_通过分析功率MOSFET管的工作特性,判断其损坏原因

0 前言目前&#xff0c;功率 MOSFET管广泛地应用于开关电源系统及其它的一些功率电子电路中&#xff0c;然而&#xff0c;在实际的应用中&#xff0c;通常&#xff0c;在一些极端的边界条件下&#xff0c;如系统的输出短路及过载测试&#xff0c;输入过电压测试以及动态的老化测…

显示多个页面退出登陆_软件测试小白如何第一次登陆时给LINUX的配置网络

接着上一期分享&#xff0c;今天分享的是虚拟机配置完成以后我们接下来怎么做首先我们进入终端登录以后先显示的是user用户点击user输入密码&#xff0c;回车或者点击sigh ln第一次进入会让你选择语音&#xff0c;你可以根据自己的喜好决定如果安装的可视化界面&#xff0c;你的…

原理 msc_计算机网络原理梳理丨无线与移动网络

目录无线网络移动网络IEEE802.11蜂窝网络移动IP网络其它典型无线网络介绍无线网络无线网络的基本结构无线主机无线链路基站网络基础设施自组织网络(Ad Hoc网络)无线链路与无线网络特性无线链路与有线链路主要区别&#xff1a;1.信号强度的衰弱2.干扰3.多径传播4.隐藏终端移动网…

二维数组最大子数组和

一&#xff0e;实验题目 求一个二维数组中和最大的子数组。 二&#xff0e;实验思路 基于我们第一次合作时求的一位数组最大子数组&#xff0c;加上一层循环来遍历二维数组中的所有子矩阵的情况。 第一步&#xff1a;先利用上次的方法求每一行的情况&#xff0c;将每行结果存入…

木炭怎么获得_木炭机一体化流程中制做木炭是怎么完成的

关注我们获得更多精彩内容木炭机一体化流程中制做木炭是怎么完成的&#xff0c;木炭机生产线中炭化炉是核心设备。炭化炉炭化过程决定了木炭质量和效果。木炭机生产线中炭化过程需要经历三个不同温度阶段。三个不同温度阶段对薪棒的炭化作用不同。炭化好坏标志着木炭机制炭效果…

【转载】网易将军令工作原理

最近开始玩梦幻手游&#xff0c;为了领以前端游的返利必须输入将军令&#xff0c;那个已经一年没用了&#xff0c;输入了几次都提示错误&#xff08;后来证实是系统繁忙而已&#xff09;&#xff0c;我以为是将军令时间不对了&#xff0c;所以用了下官网的修复功能。也对将军令…

返回数据_多层数据返回匹配值

↑↑↑点击上方图片&#xff0c;了解详情Access Switch函数示例&#xff0c;分享源码。一、问题描述&#xff1a;想实现如下功能&#xff0c;发现用iff嵌套方式太复杂&#xff0c;有没有更简单的方法&#xff1f; A1≤750 返回5.0 750&#xff1c;A1≤865 返回5.…

HDU1114 Piggy-Bank 完全背包

题意&#xff1a; 给出一个存钱罐的空罐时的质量和装了钱之后的质量&#xff0c;再给出一些硬币的质量和相应的价值&#xff0c;问存钱罐里的钱最少可能为多少。 这道题就是完全背包的问题&#xff0c;注意初始化。 完全背包与01背包不同的是第二次遍历的时候要顺序而已。 初始…

jquery datatables 学习笔记

最近项目中用到了BootStrap做后台&#xff0c;在选择表格插件的时候发现了jquery datatables。 功能是很强大&#xff0c;但是网上的例子比较少。在经过一段时间的努力可算是搞出来了。 官网地址&#xff1a;http://www.datatables.net/ 官网上的例子比较简单&#xff0c;基础的…

mysql中的double类型_MySQL中float、double、decimal三个浮点类型的区别与总结!

作者&#xff1a;极客小俊 一个专注于web技术的80后我不用拼过聪明人&#xff0c;我只需要拼过那些懒人 我就一定会超越大部分人!CSDN极客小俊&#xff0c;原创文章, B站技术分享个人博客: cnblogs.com前端htmlcssjavascript技术讨论交流群: 281499395后端phpmysqlLinux技术交流…

当电压放大电路的开路增益和输出电阻固定后_晶体管放大电路的性能分析与应用...

关于三极管共射极放大电路的基本分析方法(见附录1)&#xff0c;我们之前有聊过。本文重点与大家分享下电路的性能分析&#xff0c;尤其电路的频率响应与选频特性&#xff0c;还是非常有趣的。主要内容有&#xff1a;输入输出电阻通频带如何提高放大倍数1节5号电池可以放大电路吗…

移动设备和SharePoint 2013 - 第5部分:自定义应用

博客地址&#xff1a;http://blog.csdn.net/foxdave原文地址在该系列文章中&#xff0c;作者展示了SharePoint 2013最显著的新功能概观——对移动设备的支持。该系列文章&#xff1a;移动设备和SharePoint 2013 - 第1部分&#xff1a;概述移动设备和SharePoint 2013 - 第2部分&…

java递归实现多级菜单栏_java利用递归调用实现树形菜单的样式

一&#xff1a;需求现有以需求就是把某一个帖子的全部评论展示出来。二&#xff1a;分析关于对帖子的评论分为主评论和子评论&#xff0c;主评论就是对帖子的直接评论&#xff0c;子评论就是对评论的评论。三&#xff1a;思路先获取某一个帖子的全部主评论&#xff0c;递归判断…

mysql in 保持顺序_IN条件结果顺序问题_MySQL

bitsCN.comIN条件结果顺序问题项目中需要记录用户的浏览历史&#xff0c;我的意见是前端直接存cookie里&#xff0c;可是前端说cookie内容太多&#xff0c;要求传递id&#xff0c;后端返回数据&#xff0c;结果就产生如下的问题。1.据前端说&#xff0c;url中的数组传递是无序的…

(部分转载,部分原创)java大数类(2)

NYOJ 773 开方数 http://acm.nyist.net/JudgeOnline/problem.php?pid773 1 import java.util.Scanner;2 3 public class Main{4 public static void main(String[] args){5 int n;6 double p;7 Scanner cin new Scanner(System.in);8 w…

python3 logging com1_python-logging-基础(1)

在执行用例的时候&#xff0c;往往会遇到各种问题&#xff0c;遇到问题后很难去定位import loggingclass Logs:def __init__(self,filepath,name):#self.namename#self.filepathfilepathself.configRead_config(Config_Http)#重新定义日志名字self.loggerlogging.getLogger(sel…

python 复数求模_Python基础语法知识汇总(学习党的最爱!)

本文章包含了Python一系列基本知识&#xff0c;其中包括&#xff1a;基本数据类型&#xff08;整数&#xff0c;浮点数&#xff0c;复数&#xff0c;字符串&#xff09;&#xff1b;分支语句&#xff1b;异常处理&#xff1b;函数&#xff1b;局部变量与全局变量&#xff1b;递…

JAVA装mysql_已经安装了mysql,怎么能在java程序里使用SQL?

展开全部1、安装62616964757a686964616fe4b893e5b19e31333335323437SQLServer2000安装SQLServer2000补丁SP3安装SQLServer2000 for SP3的驱动程序(先打补丁sp3&#xff0c;再安装针对sp3的驱动程序&#xff0c;安装补丁时&#xff0c;为保险起见&#xff0c;两种验证方式的都装…

用对工具,抖音、某站视频轻松下载~

相信大部分小伙伴都有过这样的困扰&#xff0c;平时我们在刷短视频的时候就发现一段我们需要的视频。想下载时才发现&#xff0c;“保存”按钮是灰色的。 这个时候我们可以通过复制视频链接的方式来下载视频。下面给大家介绍四种万能视频下载工具&#xff0c;大家记得点赞收藏再…

flask 上传excel 前端_flask-restful编写上传图片api

Flask-RESTful是用于快速构建REST API的Flask扩展。我最近在使用Flask-Restful Vue.js写一个轻量博客时有一个前端后端上传图片的需求。在Flask-Restful的官方文档中并没有相关的内容。下面是我谷歌查找资料的总结。引入FileStorageflask-restful的参数解析中并没有文件类型&a…