Laya中使用Navmesh寻路

关于Laya中的NevMesh

Laya中使用NevMesh寻路主要依赖的是Unity的Navigation导出网格图和Astar算法,所以一般在Laya中行走区域是固定的,没办法即时更改地图的行走区域。

Astar开源地址
参考文章地址

使用步骤

添加工具代码

  1. 没有python环境的要先安装一下python环境。进入python官网/下载,然后按提示安装。安装进程中注意勾中将python目录添加到环境变量的选项,忘记的话要手动添加。
  2. 打开NevMesh.js GIT资源库。下载到本地。
  3. 在下载的NevMesh文件里找到python目录,将其复制到根目录下的空文件夹里,方便后续在命令行中使用
  4. 在Unity中先导入LayaAir3D工具。然后在下载的NevMesh文件里找到unity目录,将目录下的NavMeshExport.cs复制到Unity工程下的Editor文件夹里(或者新建工具目录)。

制作寻路模型

  1. 在Unity的window选项中打开Navigation面板,点击Object选择Mesh Renderers,在Hierarchy面板里勾选地图的模型,也可以直接勾选All在这里插入图片描述

  2. 然后在Bake面板调整地图参数,平面地图最好将Step Height设置为0避免在Laya中有些区域无法到达导致卡死,Agent Radius是角色的半径,与可行走区域有关。最后点击右下角的Bake生成地图的Navmesh数据。在这里插入图片描述
    蓝色部分就是Bake好的可行走区域。与墙体的距离可以通过Agent Radius控制。
    在这里插入图片描述

  3. 点击状态栏的LayaAir3D - NavMesh - Export,会在Assets目录下新建ExportNavMesh文件夹。里面的obj文件就是生成的Navmesh模型啦。在这里插入图片描述

  4. 这个obj文件可以发给建模生成碰撞模型给Laya使用(如果不想使用Mesh Collider或者很多Box Collider的话)。

  5. 找到粘贴好python工具的文件夹,将上述生成好的obj文件复制到文件夹下。打开命令行,切换到python文件夹。

  6. 使用命令python convert_obj_three.py -i xx.obj -o xx.json。(不会可以百度python convert_obj_three的用法)xx.obj是寻路模型的名称,xx.json是生成的json文件名称。

  7. 将生成的json文件复制到Laya里。遇到无法正确读取的情况的话可以先转换为js文件xx.js,再在Laya中新建json将数据全部复制进去。json里存贮着全部位点数据,不过我看不懂。哈哈哈哈嗝

在Laya中使用寻路

  1. 在下载的NevMesh文件里找到bulid目录,将NevMesh.js放到项目bin/libs文件夹中,将NevMesh.d.ts放到项目libs文件夹中,在bin/index.js中增加loadLib(“libs/NevMesh.js”),注意必须要在loadLib(“js/bundle.js”)前面load。在这里插入图片描述
  2. 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];
					// configMgr.commonData.deltaTime = 1;
					this._pathlen = this._pathlen + this.speed * configMgr.commonData.deltaTime;
					var tlen = Laya.Vector3.distance(p0, p1);
					// console.log("运算值:", this._pathlen, tlen);
					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;
	}
}
  1. 初始化NavMeshAgent
public playerNavMeshGroup;
initNavmeshCom(){
    
    
        // 设置寻路组件
        this.agent       = this.sprite.addComponent(NavMeshAgent);
        this.agent.speed = 3;
        // 加载寻路的json文件
        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);
    }
  1. 生成路径点
// $targetPos为目标点位置
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);
        // console.log("路径结果:", $targetPos, calculatedPath);
        if (calculatedPath && calculatedPath.length){
    
    
            var debugPath = (calculatedPath);
            // console.log("start",this.sprite.transform.position.x, this.sprite.transform.position.y, this.sprite.transform.position.z);
            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.agent.path = [this.sprite.transform.position].concat(p);
        	
        	// curNavPath为路径数组,curPathI为走到的路点下标,更换路线时一起重置。个人的使用方法。
            // this.curPathI   = 0;
            // this.curNavPath = null;
            // this.curNavPath = new Array();
            // // 移除相同的点
            // this.curNavPath = this.removeSamePos(this.agent.path);
        }
    }

猜你喜欢

转载自blog.csdn.net/the_vnas/article/details/124444108