mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-06-26 11:24:46 +00:00
193 lines
6.5 KiB
C#
193 lines
6.5 KiB
C#
using System.Collections.Generic;
|
|
using DotRecast.Core.Numerics;
|
|
using DotRecast.Detour;
|
|
using DotRecast.Detour.Crowd;
|
|
using DotRecast.Recast.Geom;
|
|
using DotRecast.Recast.Toolset;
|
|
using DotRecast.Recast.Toolset.Builder;
|
|
using JNGame.Map.DotRecast.Util;
|
|
using JNGame.Math;
|
|
using Newtonsoft.Json;
|
|
using UnityEngine;
|
|
|
|
namespace JNGame.Map.DotRecast
|
|
{
|
|
public class DotRecastRoot
|
|
{
|
|
|
|
//导航数据
|
|
public DtNavMesh NavMesh;
|
|
|
|
//导航查询
|
|
public DtNavMeshQuery Query { private set; get; }
|
|
|
|
//智能体避障
|
|
public DtCrowd Crowd { private set; get; }
|
|
private Dictionary<ulong, DtCrowdAgent> agents;
|
|
|
|
public DotRecastRoot(MeshData data)
|
|
{
|
|
agents = new Dictionary<ulong, DtCrowdAgent>();
|
|
//初始化导航数据
|
|
InitNavMesh(data);
|
|
//初始化避障数据
|
|
InitCrowd(data);
|
|
}
|
|
|
|
//更新
|
|
public void Update(LFloat dt)
|
|
{
|
|
Crowd.Update(dt,null);
|
|
}
|
|
|
|
public DtCrowdAgentParams GetAgentParams()
|
|
{
|
|
int updateFlags = DtCrowdAgentUpdateFlags.DT_CROWD_ANTICIPATE_TURNS |
|
|
DtCrowdAgentUpdateFlags.DT_CROWD_OPTIMIZE_VIS |
|
|
DtCrowdAgentUpdateFlags.DT_CROWD_OPTIMIZE_TOPO |
|
|
DtCrowdAgentUpdateFlags.DT_CROWD_OBSTACLE_AVOIDANCE;
|
|
DtCrowdAgentParams ap = new DtCrowdAgentParams();
|
|
ap.radius = (LFloat)0.6f;
|
|
ap.height = (LFloat)2f;
|
|
ap.maxAcceleration = (LFloat)8.0f;
|
|
ap.maxSpeed = (LFloat)6f;
|
|
ap.collisionQueryRange = ap.radius * (LFloat)12f;
|
|
ap.pathOptimizationRange = ap.radius * (LFloat)30f;
|
|
ap.updateFlags = updateFlags;
|
|
ap.obstacleAvoidanceType = 0;
|
|
ap.separationWeight = (LFloat)2f;
|
|
return ap;
|
|
}
|
|
|
|
//初始化导航
|
|
private void InitNavMesh(MeshData data)
|
|
{
|
|
var vertices = new LFloat[data.vertices.Length * 3];
|
|
for (int i = 0; i < data.vertices.Length; ++i)
|
|
{
|
|
vertices[i * 3 + 0] = data.vertices[i].x;
|
|
vertices[i * 3 + 1] = data.vertices[i].y;
|
|
vertices[i * 3 + 2] = data.vertices[i].z;
|
|
}
|
|
|
|
var bmin = RcVecUtils.Create(vertices);
|
|
var bmax = RcVecUtils.Create(vertices);
|
|
for (int i = 1; i < vertices.Length / 3; i++)
|
|
{
|
|
bmin = RcVecUtils.Min(bmin, vertices, i * 3);
|
|
bmax = RcVecUtils.Max(bmax, vertices, i * 3);
|
|
}
|
|
|
|
var geom = new DefaultInputGeomProvider(vertices,data.triangles);
|
|
var builder = new TileNavMeshBuilder();
|
|
var settings = new RcNavMeshBuildSettings();
|
|
|
|
settings.cellSize = (LFloat)1f;
|
|
var result = builder.Build(geom, settings);
|
|
|
|
NavMesh = result.NavMesh;
|
|
Query = new DtNavMeshQuery(NavMesh);
|
|
}
|
|
|
|
//初始化避障
|
|
private void InitCrowd(MeshData data)
|
|
{
|
|
DtCrowdConfig config = new DtCrowdConfig((LFloat)0.6f);
|
|
Crowd = new DtCrowd(config, NavMesh);
|
|
DtObstacleAvoidanceParams option = new DtObstacleAvoidanceParams();
|
|
option.velBias = (LFloat)0.5f;
|
|
option.adaptiveDivs = 5;
|
|
option.adaptiveRings = 2;
|
|
option.adaptiveDepth = 1;
|
|
Crowd.SetObstacleAvoidanceParams(0, option);
|
|
}
|
|
|
|
//添加避障
|
|
public void AddAgent(ulong id,RcVec3f start)
|
|
{
|
|
DelAgent(id);
|
|
agents.Add(id,Crowd.AddAgent(start, GetAgentParams()));
|
|
}
|
|
public void AddAgent(ulong id,RcVec3f start,DtCrowdAgentParams agentParams)
|
|
{
|
|
DelAgent(id);
|
|
agents.Add(id,Crowd.AddAgent(start, agentParams));
|
|
}
|
|
|
|
//添加避障
|
|
public void DelAgent(ulong id)
|
|
{
|
|
if (agents.ContainsKey(id))
|
|
{
|
|
Crowd.RemoveAgent(agents[id]);
|
|
agents.Remove(id);
|
|
}
|
|
}
|
|
|
|
//移动避障
|
|
public void MoveAgent(ulong id,RcVec3f move)
|
|
{
|
|
|
|
DtCrowdAgent agent = agents[id];
|
|
Query.FindNearestPoly(move, Crowd.GetQueryExtents(), Crowd.GetFilter(0), out var nearestRef, out var nearestPt, out var _);
|
|
Crowd.RequestMoveTarget(agent, nearestRef, nearestPt);
|
|
|
|
}
|
|
|
|
//向量移动避障
|
|
public void VectorMoveAgent(ulong id,RcVec3f vector)
|
|
{
|
|
DtCrowdAgent agent = agents[id];
|
|
Crowd.RequestMoveVelocity(agent,vector);
|
|
}
|
|
|
|
//获取避障
|
|
public DtCrowdAgent GetAgent(ulong id)
|
|
{
|
|
agents.TryGetValue(id, out var value);
|
|
return value;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 查询导航
|
|
/// </summary>
|
|
/// <param name="pos"></param>
|
|
/// <returns></returns>
|
|
public List<DtStraightPath> FindPath(LVector3 start,LVector3 end)
|
|
{
|
|
var start1 = new RcVec3f(start.x,start.y,start.z);
|
|
var end1 = new RcVec3f(end.x,end.y,end.z);
|
|
var half = new RcVec3f(1000, 1000, 1000);
|
|
var filter = new DtQueryDefaultFilter();
|
|
Query.FindNearestPoly(start1, half, filter, out var startRef, out var startPt, out var _);
|
|
Query.FindNearestPoly(end1, half, filter, out var endRef, out var endPt, out var _);
|
|
var path = new List<long>();
|
|
DtStatus status = Query.FindPath(startRef,endRef,startPt, endPt, filter,ref path, DtFindPathOption.AnyAngle);
|
|
var paths = new List<DtStraightPath>();
|
|
Query.FindStraightPath(startPt, endPt, path, path.Count, ref paths, 256, 0);
|
|
return paths;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 返回最近点
|
|
/// </summary>
|
|
/// <param name="pos"></param>
|
|
/// <returns></returns>
|
|
public LVector3 GetNearbyPoints(LVector3 pos)
|
|
{
|
|
DtStatus status = Query.FindNearestPoly(
|
|
new RcVec3f(pos.x, pos.y, pos.z),
|
|
new RcVec3f(1000, 1000, 1000),
|
|
new DtQueryDefaultFilter(),
|
|
out var refs,
|
|
out var nearestPt,
|
|
out var _);
|
|
return new LVector3((LFloat)nearestPt.X, (LFloat)nearestPt.Y, (LFloat)nearestPt.Z);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} |