大家好,欢迎大家关注我的博客,我是秦元培,我的博客地址是blog.csdn.net/qinyuanpei。
这段时间博主将大部分的精力都放在了研究官方演示样例项目上,主要是希望能够从中挖掘出有价值的东西分享给大家。这样博主和大家能够共同学习。好了,那么今天博主想和大家分享的是自己主动寻路与Mecanim动画系统结合起来实现的一个小案例,希望对大家学习Unity3D能够有所帮助。
博主以前告诉大家。博主是一个仙剑迷,平时学习编程累了的时候,博主就会玩玩仙剑。如图是博主偶尔回去玩玩的《新仙剑OL》。仙剑的网游化道路似乎一直不曾平坦,从最初的《仙剑OL》到如今的《新仙剑OL》,仙剑的网游化一直处于不温不火的状态。
尽管博主比較反感网游。但是作为一款由博主喜欢的单机游戏改编的网游,博主还是忍不住去尝试了一下。基于Unity3D的《新仙剑OL》尽管从画面质量上与同类网页游戏拉开了距离,然而在游戏的玩法和体验上依旧没有摆脱国产网游的固定模式,博主叹息之余。便依据这款游戏在自己主动寻路上的设计写出了这篇文章。说到自己主动寻路。这差点儿是眼下全部网页游戏的标准配置了。在博主看来。自己主动寻路在简化玩家寻找目标的途径的同一时候。弱化了玩家的參与,使得本该玩家自行探索的游戏世界。变成了枯燥无味的鼠标游戏。曾几何时,我们在迷宫中探索着远方的路,曾几何时,我们开启机关、破解阵法收获着游戏的乐趣。在这样一个快节奏的时代,我们却仅仅能一遍遍地回忆着过去的生活。那个时候没有电脑、没有智能手机、没有电影.....但是我们却经常怀念那个时候简单的生活,所以,小时候,幸福是件简单的事情,长大后,简单是件幸福的事情。尽管博主讨厌自己主动寻路这一设定。但是这与我们学习Unity3D无关。由于我们仅仅是为了更好地使用这个引擎来做出好的游戏产品。好了,闲话少叙,我们继续说《新仙剑OL》中的自己主动寻路,在游戏中玩家能够通过鼠标来控制人物,假设距离较远。则人物会以奔跑的形式到达目标位置,否则人物将步行到目标位置。而这就是我们今天想要实现的效果。好了。以下我们正式開始今天的内容,今天的内容呢,分为两个部分,第一部分讲述Mecanim动画系统,第二部分讲述自己主动寻路。
第一部分:Mecanim动画系统
在这一部分,我们主要讲的是动画的切换,由于从刚才的描写叙述中我们知道,角色的动画有三种状态,即Idle、Walk、Run。
通过前面的学习呢。我们知道通过Mecanim动画系统的状态机我们能够非常方便地实现动画状态的切换。由此我们就能够理出一个大致的思路,通过鼠标点击获取鼠标位置,然后我们利用射线的方法,从摄像机发射一条经过该点的射线,则射线与地面的交点就是我们寻路的目标点,我们通过计算角色与目标点之间的距离来确定角色要採用什么样的动画,而寻路则交给Unity3D的Nav Mesh Agent组件来完毕,这就是我们今天的实现思路,事实上博主在之前的一篇文章中已经讲述过这样的方法,这里只是是在之前的基础上。结合Mecanim动画系统和自己主动寻路组件做了些改进而已。好了。我们打开我们的项目,如图,是博主创建的一个简单的场景,我们今天的内容就以这个场景来展开:
接下来。我们利用Mecanim动画系统来设计角色的动画,如图,在今天的项目中角色仅仅有三种状态,因此我们能够将三种状态连接起来,这里我们定义了两个Bool类型的变量IsWalk和IsRun,默觉得False,这是我们今天用来切换动画的两个变量开关。
剩下的工作就是编写脚本来控制动画了,这一步我们放在第二部分来讲。
第二部分:自己主动寻路
在这一部分。我们首先要对场景进行烘培,由于Nav Mesh Agent组件是依据网格来计算寻路的路线的,所以烘培的过程相当于是在保存场景中的网格信息。仅仅有这样我们才干够使用Unity3D的寻路组件。
以下我们就来解说下场景的烘焙:
首先我们选中场景中不须要与玩家发生交互的物体,或者能够觉得这些物体是我们的角色须要避开的障碍物,将其设置为Static,如图:
接下来我们通过Windowe->Navigation命令打开Navigation窗体,此时被选中的物体以深色显示。确认无误后,点击Bakebutton对场景进行烘焙,这样我们就完毕了场景的烘焙工作。
好了。以下我们选中场景中的角色。为其加入Nav Mesh Agent组件。此时场景中会显示出绿色的区域。其含义是这些区域角色能够到达。关于Nav Mesh Agent组件的參数。大家能够自行查阅API文档,这里不做解释了,好了,以下我们编写脚本:
using UnityEngine;
using System.Collections; public class PeopleScripts : MonoBehaviour { //动画组件
private Animator mAnim;
//移动速度
public float MoveSpeed=2.5F;
//寻路组件
private NavMeshAgent mAgent;
//寻路目标标记
private GameObject Ball; //寻路标记预制件
public GameObject PrefabBall; void Start () {
//获取动画组件
mAnim=GetComponent<Animator>();
//获取寻路组件
mAgent=GetComponent<NavMeshAgent>();
} void Update () {
//按下鼠标左键
if(Input.GetMouseButton(0))
{
//获取鼠标位置
Vector3 mPos=Input.mousePosition;
//利用射线法取得目标位置
Ray mRay=Camera.main.ScreenPointToRay(mPos);
RaycastHit mHit;
if(Physics.Raycast(mRay,out mHit))
{
//这里相应于场景中的地面、墙体、楼梯三种结构
if(mHit.collider.tag=="Ground" || mHit.collider.tag=="Wall" || mHit.collider.tag=="Ti")
{
//获得目标位置
Vector3 mTarget=mHit.point;
//使用全然面向目标的旋转
transform.LookAt(mTarget);
//使用平滑转身转向目标
//SmoothRotate(mTarget);
//计算距离
float mDistance=Vector3.Distance(mTarget,this.transform.position);
//当距离大于4时奔跑到目标位置。否则步行到目标位置
if(mDistance>4F){
mAnim.SetBool("IsRun",true);
}else{
mAnim.SetBool("IsWalk",true);
} //依据不同的结构生成不同高度的寻路目标标记
if(mHit.collider.tag=="Ground"){
//标记寻路目标
Ball=(GameObject)Instantiate(PrefabBall,new Vector3(mTarget.x,0.5F,mTarget.z),
Quaternion.identity);
}else{
//标记寻路目标
Ball=(GameObject)Instantiate(PrefabBall,new Vector3(mTarget.x,3.0F,mTarget.z),
Quaternion.identity);
}
//设置寻路目标
mAgent.SetDestination(mTarget);
}
}
}
} void OnTriggerEnter(Collider mCollider)
{
if(mCollider.tag=="Ball")
{
//获取目标标记
GameObject mBall=mCollider.gameObject;
//销毁目标标记
Destroy(mBall);
//将角色状态设为Idle
mAnim.SetBool("IsRun",false);
mAnim.SetBool("IsWalk",false);
}
} //平滑转身,參考自Stealth
void SmoothRotate(Vector3 target)
{
//构造目标朝向
Quaternion targetRotation = Quaternion.LookRotation(target, Vector3.up);
//对目标朝向进行插值
Quaternion mRotation = Quaternion.Lerp(transform.rotation, targetRotation, 15F * Time.deltaTime);
//赋值
transform.rotation=mRotation;
}
}
最后,我们来看看最后的效果吧。为了让大家更清楚的看到寻路的效果,博主在寻路点处添加了一个紫色的小球,便于大家观察:
每日箴言:别低头,别诉苦。他们以为你无坚不摧,那就随他们喜欢;别人不知道的,你不是必需反驳给他听。
转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/38981669