提交寻路

This commit is contained in:
PC-20230316NUNE\Administrator
2024-02-06 18:57:13 +08:00
parent 16d943ab6b
commit 0a12c49bf1
49 changed files with 9046 additions and 38 deletions

View File

@@ -0,0 +1,21 @@
using System.Collections;
using System.Collections.Generic;
using Game.Plugins.JNGame.Sync.Frame.AstarPath.RVO;
using Plugins.JNGame.Sync.Frame.AStar;
using Script.battle;
using UnityEngine;
public class GRVO02WorldMode : GBaseMode<Object>
{
//初始化3D避障
[HideInInspector]
public JNRVOSimulator Simulator = new(MovementPlane.XZ);
//初始化寻路
[HideInInspector]
public JNAStarPath AStar = new();
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a85dc713c3eb290448e178323fed525c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,227 @@
using System.Collections;
using System.Collections.Generic;
using Game.Plugins.App.Sync;
using Game.Plugins.JNGame.Sync.Frame.AStar.Util;
using Game.Plugins.JNGame.Sync.Frame.AstarPath.AI;
using Game.Plugins.JNGame.Sync.Frame.AstarPath.RVO;
using Plugins.JNGame.Sync.Frame.AStar;
using Plugins.JNGame.Sync.Frame.game.Time;
using Plugins.JNGame.Util;
using UnityEngine;
public class GRVO02WorldPlayerController : JNGSyncFrameDefault
{
//模式
public GRVO02WorldMode mode;
//添加寻路AI
private JNAISeeker ai;
//添加RVO避障 控制器 (里面默认使用避障)
private JNRVOController rvo;
//目标位置
private Vector3 target;
//是否正在查询位置
private bool canSearchAgain = true;
//当前路径
private JNPath path = null;
// 向量路径
List<Vector3> vectorPath;
// waypoint进度
private int wp = 0;
//移动距离
public float moveNextDist = 1;
//下一次寻路 (主要目的是为了在寻路过程中引入一定的随机性和变化,特别是在动态环境或者存在移动障碍物的场景中。这样的设计可以帮助代理(例如游戏中的角色)更加智能和灵活地适应环境的变化 )
//如果不重新计算路径,代理可能会遇到障碍物而停止移动,或者沿着一条不再是最佳(甚至不再可通行)的路径移动
public float nextRepath = 1;
//平滑停止
public float slowdownDistance = 1;
//最大速度
public float maxSpeed = 10;
//碰撞层级
public LayerMask groundMask;
public override void OnSyncLoad()
{
base.OnSyncLoad();
//初始化寻路AI
ai = new JNAISeeker(mode.AStar);
//初始化避障控制器
rvo = new JNRVOController(mode.Simulator,gameObject);
}
//设置移动位置
public void SetTarget (Vector3 target) {
this.target = target;
RecalculatePath();
}
/// 重新计算到达目标点的路径
public void RecalculatePath() {
//不允许再次搜索路径
canSearchAgain = false;
//下一次寻路时间
nextRepath = GetSync().Time.time + 2;
// 启动路径搜索,传入当前位置、目标位置和路径搜索完成的回调函数
ai.StartPath(transform.position, target, OnPathComplete);
}
/// <summary>
/// 路径搜索完成时的回调函数
/// <param name="_p">搜索得到的路径</param>
public void OnPathComplete(JNPath _p) {
// 将传入的路径尝试转换为ABPath类型
JNABPath p = _p as JNABPath;
// 允许再次搜索路径
canSearchAgain = true;
// 如果之前存在路径对象,则释放对它的引用
if (path != null) path.Release(this);
// 更新当前路径对象为搜索得到的新路径
path = p;
// 声明对该路径的所有权
p.Claim(this);
// 如果路径搜索出错(比如没有找到可行路径)
if (p.error) {
//重置数据
// 重置waypoint进度
wp = 0;
// 清空向量路径
vectorPath = null;
// 提前返回,不再继续执行后续代码
return;
}
// 获取路径的起始点
Vector3 p1 = p.originalStartPoint;
// 获取代理当前的位置
Vector3 p2 = transform.position;
// 将起始点的y坐标设置为当前位置的y坐标确保路径在同一水平面上
p1.y = p2.y;
// 计算当前位置与起始点之间的距离
float d = (p2 - p1).magnitude;
// 重置waypoint进度
wp = 0;
// 更新向量路径为搜索得到的新路径的向量表示
vectorPath = p.vectorPath;
Vector3 waypoint; // 用于存储当前waypoint的位置
// 如果定义了每次移动的最大距离moveNextDist > 0
if (moveNextDist > 0) {
// 遍历从起始点到当前位置的距离每次增加moveNextDist的60%
for (float t = 0; t <= d; t += moveNextDist * 0.6f) {
// 递减waypoint索引因为我们是从路径的末尾开始向前遍历
wp--;
// 计算当前位置的向量表示
Vector3 pos = p1 + (p2 - p1) * t;
// 循环遍历向量路径直到找到一个waypoint使得代理从当前位置移动到该waypoint的距离
// 大于或等于moveNextDist或者已经到达向量路径的最后一个waypoint
do {
// 递增waypoint索引
wp++;
// 获取向量路径中当前waypoint的位置
waypoint = vectorPath[wp];
// 循环条件代理到当前waypoint的距离小于moveNextDist并且还没有到达向量路径的最后一个waypoint
} while (rvo.To2D(pos - waypoint).sqrMagnitude < moveNextDist * moveNextDist && wp != vectorPath.Count - 1);
}
}
}
public override void OnSyncUpdate(int dt, JNFrameInfo frame, Object input)
{
base.OnSyncUpdate(dt, frame, input);
// 检查是否需要重新计算路径
if (GetSync().Time.time >= nextRepath && canSearchAgain)
{
RecalculatePath();
}
Vector3 pos = transform.position;
// 如果存在路径且路径不为空
if (vectorPath != null && vectorPath.Count != 0)
{
// 遍历路径直到找到下一个要到达的点
while ((rvo.To2D(pos - vectorPath[wp]).sqrMagnitude < moveNextDist * moveNextDist && wp != vectorPath.Count - 1) || wp == 0)
{
wp++;
}
// 计算路径段上的点
var p1 = vectorPath[wp - 1];
var p2 = vectorPath[wp];
var t = VectorMath.LineCircleIntersectionFactor(rvo.To2D(transform.position), rvo.To2D(p1), rvo.To2D(p2), moveNextDist);
t = Mathf.Clamp01(t);
Vector3 waypoint = Vector3.Lerp(p1, p2, t);
// 计算到路径终点的剩余距离
float remainingDistance = rvo.To2D(waypoint - pos).magnitude + rvo.To2D(waypoint - p2).magnitude;
for (int i = wp; i < vectorPath.Count - 1; i++)
{
remainingDistance += rvo.To2D(vectorPath[i + 1] - vectorPath[i]).magnitude;
}
// 设置目标点和期望速度
var rvoTarget = (waypoint - pos).normalized * remainingDistance + pos;
var desiredSpeed = Mathf.Clamp01(remainingDistance / slowdownDistance) * maxSpeed;
// // 绘制一条从当前位置到路径点的红色线段用于调试
// Debug.DrawLine(transform.position, waypoint, Color.red);
// 设置RVO控制器的目标点和速度
rvo.SetTarget(rvoTarget, desiredSpeed, maxSpeed);
}
else
{
// 如果没有路径,则静止不动
rvo.SetTarget(pos, maxSpeed, maxSpeed);
}
// 从RVO控制器获取处理过的移动增量并移动角色
var movementDelta = rvo.CalculateMovementDelta(Time.deltaTime);
pos += movementDelta;
// 如果移动增量足够大,则旋转角色以面向移动方向
if (Time.deltaTime > 0 && movementDelta.magnitude / Time.deltaTime > 0.01f)
{
var rot = transform.rotation;
var targetRot = Quaternion.LookRotation(movementDelta, rvo.To3D(Vector2.zero, 1));
const float RotationSpeed = 5;
if (rvo.movementPlane == MovementPlane.XY)
{
targetRot = targetRot * Quaternion.Euler(-90, 180, 0);
}
transform.rotation = Quaternion.Slerp(rot, targetRot, Time.deltaTime * RotationSpeed);
}
// 如果角色在XZ平面上移动确保它保持在地面上
if (rvo.movementPlane == MovementPlane.XZ)
{
RaycastHit hit;
if (Physics.Raycast(pos + Vector3.up, Vector3.down, out hit, 2, groundMask))
{
pos.y = hit.point.y;
}
}
// 更新角色的位置
transform.position = pos;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a83c78eaa47b3244c9974793e439d257
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: