关于Laya中的NevMesh
Laya中使用NevMesh寻路主要依赖的是Unity的Navigation导出网格图和Astar算法,所以一般在Laya中行走区域是固定的,没办法即时更改地图的行走区域。
Astar开源地址 参考文章地址
使用步骤
添加工具代码
- 没有python环境的要先安装一下python环境。进入python官网/下载,然后按提示安装。安装进程中注意勾中将python目录添加到环境变量的选项,忘记的话要手动添加。
- 打开NevMesh.js GIT资源库。下载到本地。
- 在下载的NevMesh文件里找到python目录,将其复制到根目录下的空文件夹里,方便后续在命令行中使用。
- 在Unity中先导入LayaAir3D工具。然后在下载的NevMesh文件里找到unity目录,将目录下的NavMeshExport.cs复制到Unity工程下的Editor文件夹里(或者新建工具目录)。
制作寻路模型
-
在Unity的window选项中打开Navigation面板,点击Object选择Mesh Renderers,在Hierarchy面板里勾选地图的模型,也可以直接勾选All。 -
然后在Bake面板调整地图参数,平面地图最好将Step Height设置为0避免在Laya中有些区域无法到达导致卡死,Agent Radius是角色的半径,与可行走区域有关。最后点击右下角的Bake生成地图的Navmesh数据。 蓝色部分就是Bake好的可行走区域。与墙体的距离可以通过Agent Radius控制。 -
点击状态栏的LayaAir3D - NavMesh - Export,会在Assets目录下新建ExportNavMesh文件夹。里面的obj文件就是生成的Navmesh模型啦。 -
这个obj文件可以发给建模生成碰撞模型给Laya使用(如果不想使用Mesh Collider或者很多Box Collider的话)。 -
找到粘贴好python工具的文件夹,将上述生成好的obj文件复制到文件夹下。打开命令行,切换到python文件夹。 -
使用命令python convert_obj_three.py -i xx.obj -o xx.json。(不会可以百度python convert_obj_three的用法)xx.obj是寻路模型的名称,xx.json是生成的json文件名称。 -
将生成的json文件复制到Laya里。遇到无法正确读取的情况的话可以先转换为js文件xx.js,再在Laya中新建json将数据全部复制进去。
在Laya中使用寻路
- 在下载的NevMesh文件里找到bulid目录,将NevMesh.js放到项目bin/libs文件夹中,将NevMesh.d.ts放到项目libs文件夹中,在bin/index.js中增加loadLib(“libs/NevMesh.js”),注意必须要在loadLib(“js/bundle.js”)前面load。
- typescript中的路径生成的代码如下,NevMesh文件里scr目录有其他的代码可供参考
import configMgr from "../mgr/ConfigMgr";
export default class NavMeshAgent extends Laya.Script {
constructor() {
super();
}
public navMeshGroup;
public updateRotation;
public _pathPending;
public _path;
public _pathp;
public _pathlen;
public _remainingDistance;
public destination;
public speed;
public steeringTarget;
public _velocity;
public out;
onAwake(): void {
this.navMeshGroup = null;
this.enabled = false;
this.updateRotation = false;
this._pathPending = false;
this._path = null;
this._pathp = 0;
this._pathlen = 0;
this._remainingDistance = 1;
this.destination = null;
this.speed = 1;
this.steeringTarget = new Laya.Vector3();
this._velocity = new Laya.Vector3();
this.out = new Laya.Vector3();
}
onUpdate() {
if (this.enabled) {
var now = (this.owner as Laya.Sprite3D).transform.position;
if (this._path) {
var v = new Laya.Vector3;
var tp = null;
for (var i = this._pathp; i < this._path.length - 1; i++) {
var p0 = this._path[i];
var p1 = this._path[i + 1];
this._pathlen = this._pathlen + this.speed * configMgr.commonData.deltaTime;
var tlen = Laya.Vector3.distance(p0, p1);
if (this._pathlen > tlen) {
this._pathlen -= tlen;
this._pathp++;
}
else {
tp = p0.clone();
p1.cloneTo(this.steeringTarget);
Laya.Vector3.subtract(p1, p0, v);
Laya.Vector3.normalize(v, v);
Laya.Vector3.scale(v, this._pathlen, v);
Laya.Vector3.add(p0, v, tp);
break;
}
}
if (tp == null) {
this._pathPending = false;
tp = this._path[this._path.length - 1];
this._path[this._path.length - 1].cloneTo(this.steeringTarget);
this.enabled = false;
}
((this.owner as Laya.Sprite3D).getChildAt(0) as Laya.Sprite3D).transform.lookAt(new Laya.Vector3(-tp.x, -tp.y, -tp.z),
new Laya.Vector3(0, 1, 0),
true);
(this.owner as Laya.Sprite3D).transform.position = tp;
} else {
this.out.x = now.x + this.velocity.x * Laya.timer.delta / 1000;
this.out.y = now.y + this.velocity.y * Laya.timer.delta / 1000;
this.out.z = now.z + this.velocity.z * Laya.timer.delta / 1000;
if (this.navMeshGroup == null) {
this.out.cloneTo(now);
(this.owner as Laya.Sprite3D).transform.position = now;
}
}
}
}
get remainingDistance() {
if (this.destination && this.owner) {
return Laya.Vector3.distance(this.destination, (this.owner as Laya.Sprite3D).transform.position);
}
return this._remainingDistance;
}
set remainingDistance(value) {
this._remainingDistance = value;
}
get velocity() {
return this._velocity;
}
set velocity(value) {
this._velocity = value;
this.destination = null;
}
get path() {
return this._path;
}
set path(value) {
this._path = value;
if (value) {
this._pathPending = true;
} else {
this._pathPending = false;
}
this._pathp = 0;
this._pathlen = 0;
}
}
- 初始化NavMeshAgent
public playerNavMeshGroup;
initNavmeshCom(){
this.agent = this.sprite.addComponent(NavMeshAgent);
this.agent.speed = 3;
let json = Laya.loader.getRes(configMgr.commonData.navUrl);
let zoneNodes = NevMesh.buildNodesByJson(json);
NevMesh.setZoneData(this.nodeName, zoneNodes);
this.playerNavMeshGroup = NevMesh.getGroup(this.nodeName, this.sprite.transform.position);
}
- 生成路径点
findPath($targetPos : Laya.Vector3){
$targetPos.y = this.ownerPos.y;
let startPos = new Laya.Vector3(this.ownerPos.x, this.ownerPos.y, this.ownerPos.z);
let calculatedPath = NevMesh.findPath(startPos, $targetPos, this.nodeName, this.playerNavMeshGroup);
if (calculatedPath && calculatedPath.length){
var debugPath = (calculatedPath);
var p = [];
for (var i = 0;i < debugPath.length;i++){
p.push(new Laya.Vector3(debugPath[i].x,debugPath[i].y+.1,debugPath[i].z));
}
this.agent.path = [this.sprite.transform.position].concat(p);
}
}
|