2023-03-14 08:02:43 +03:00
|
|
|
/*
|
|
|
|
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
|
|
|
|
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
2023-03-15 17:00:29 +03:00
|
|
|
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
|
2023-03-14 08:02:43 +03:00
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
|
|
claim that you wrote the original software. If you use this software
|
|
|
|
in a product, an acknowledgment in the product documentation would be
|
|
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
2023-03-28 19:52:26 +03:00
|
|
|
using DotRecast.Core;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:09:10 +03:00
|
|
|
namespace DotRecast.Detour.Crowd
|
|
|
|
{
|
2023-03-25 09:43:20 +03:00
|
|
|
using static DotRecast.Core.RecastMath;
|
2023-03-16 19:09:10 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// Represents an agent managed by a #dtCrowd object.
|
|
|
|
/// @ingroup crowd
|
|
|
|
public class CrowdAgent
|
|
|
|
{
|
|
|
|
/// The type of navigation mesh polygon the agent is currently traversing.
|
|
|
|
/// @ingroup crowd
|
|
|
|
public enum CrowdAgentState
|
|
|
|
{
|
|
|
|
DT_CROWDAGENT_STATE_INVALID,
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// < The agent is not in a valid state.
|
|
|
|
DT_CROWDAGENT_STATE_WALKING,
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// < The agent is traversing a normal navigation mesh polygon.
|
|
|
|
DT_CROWDAGENT_STATE_OFFMESH, /// < The agent is traversing an off-mesh connection.
|
|
|
|
};
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
public enum MoveRequestState
|
|
|
|
{
|
|
|
|
DT_CROWDAGENT_TARGET_NONE,
|
|
|
|
DT_CROWDAGENT_TARGET_FAILED,
|
|
|
|
DT_CROWDAGENT_TARGET_VALID,
|
|
|
|
DT_CROWDAGENT_TARGET_REQUESTING,
|
|
|
|
DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE,
|
|
|
|
DT_CROWDAGENT_TARGET_WAITING_FOR_PATH,
|
|
|
|
DT_CROWDAGENT_TARGET_VELOCITY,
|
|
|
|
};
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
public readonly long idx;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState)
|
|
|
|
public CrowdAgentState state;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// True if the agent has valid path (targetState == DT_CROWDAGENT_TARGET_VALID) and the path does not lead to the
|
|
|
|
/// requested position, else false.
|
|
|
|
public bool partial;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// The path corridor the agent is using.
|
|
|
|
public PathCorridor corridor;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// The local boundary data for the agent.
|
|
|
|
public LocalBoundary boundary;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// Time since the agent's path corridor was optimized.
|
|
|
|
public float topologyOptTime;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// The known neighbors of the agent.
|
|
|
|
public List<Crowd.CrowdNeighbour> neis = new List<Crowd.CrowdNeighbour>();
|
|
|
|
|
|
|
|
/// The desired speed.
|
|
|
|
public float desiredSpeed;
|
|
|
|
|
2023-03-28 18:03:33 +03:00
|
|
|
public Vector3f npos = new Vector3f();
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
/// < The current agent position. [(x, y, z)]
|
2023-03-28 18:03:33 +03:00
|
|
|
public Vector3f disp = new Vector3f();
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
/// < A temporary value used to accumulate agent displacement during iterative
|
|
|
|
/// collision resolution. [(x, y, z)]
|
2023-03-28 18:03:33 +03:00
|
|
|
public Vector3f dvel = new Vector3f();
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
/// < The desired velocity of the agent. Based on the current path, calculated
|
|
|
|
/// from
|
|
|
|
/// scratch each frame. [(x, y, z)]
|
2023-03-28 18:03:33 +03:00
|
|
|
public Vector3f nvel = new Vector3f();
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
/// < The desired velocity adjusted by obstacle avoidance, calculated from scratch each
|
|
|
|
/// frame. [(x, y, z)]
|
2023-03-28 18:03:33 +03:00
|
|
|
public Vector3f vel = new Vector3f();
|
2023-03-16 19:48:49 +03:00
|
|
|
|
|
|
|
/// < The actual velocity of the agent. The change from nvel -> vel is
|
|
|
|
/// constrained by max acceleration. [(x, y, z)]
|
|
|
|
/// The agent's configuration parameters.
|
|
|
|
public CrowdAgentParams option;
|
|
|
|
|
|
|
|
/// The local path corridor corners for the agent.
|
|
|
|
public List<StraightPathItem> corners = new List<StraightPathItem>();
|
|
|
|
|
|
|
|
public MoveRequestState targetState;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// < State of the movement request.
|
|
|
|
public long targetRef;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// < Target polyref of the movement request.
|
2023-03-28 18:03:33 +03:00
|
|
|
public Vector3f targetPos = new Vector3f();
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// < Target position of the movement request (or velocity in case of
|
|
|
|
/// DT_CROWDAGENT_TARGET_VELOCITY).
|
|
|
|
public PathQueryResult targetPathQueryResult;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// < Path finder query
|
|
|
|
public bool targetReplan;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// < Flag indicating that the current path is being replanned.
|
|
|
|
public float targetReplanTime;
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
/// <Time since the agent's target was replanned.
|
|
|
|
public float targetReplanWaitTime;
|
|
|
|
|
|
|
|
public CrowdAgentAnimation animation;
|
|
|
|
|
|
|
|
public CrowdAgent(int idx)
|
|
|
|
{
|
|
|
|
this.idx = idx;
|
|
|
|
corridor = new PathCorridor();
|
|
|
|
boundary = new LocalBoundary();
|
|
|
|
animation = new CrowdAgentAnimation();
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
public void integrate(float dt)
|
|
|
|
{
|
|
|
|
// Fake dynamic constraint.
|
|
|
|
float maxDelta = option.maxAcceleration * dt;
|
2023-03-28 19:52:26 +03:00
|
|
|
Vector3f dv = vSub(nvel, vel);
|
2023-03-16 19:48:49 +03:00
|
|
|
float ds = vLen(dv);
|
|
|
|
if (ds > maxDelta)
|
|
|
|
dv = vScale(dv, maxDelta / ds);
|
|
|
|
vel = vAdd(vel, dv);
|
|
|
|
|
|
|
|
// Integrate
|
|
|
|
if (vLen(vel) > 0.0001f)
|
|
|
|
npos = vMad(npos, vel, dt);
|
|
|
|
else
|
2023-03-28 19:52:26 +03:00
|
|
|
vSet(ref vel, 0, 0, 0);
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
public bool overOffmeshConnection(float radius)
|
|
|
|
{
|
|
|
|
if (0 == corners.Count)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool offMeshConnection = ((corners[corners.Count - 1].getFlags()
|
|
|
|
& NavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
|
|
|
|
? true
|
|
|
|
: false;
|
|
|
|
if (offMeshConnection)
|
|
|
|
{
|
|
|
|
float distSq = vDist2DSqr(npos, corners[corners.Count - 1].getPos());
|
|
|
|
if (distSq < radius * radius)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
2023-03-16 19:48:49 +03:00
|
|
|
public float getDistanceToGoal(float range)
|
|
|
|
{
|
|
|
|
if (0 == corners.Count)
|
|
|
|
return range;
|
|
|
|
|
|
|
|
bool endOfPath = ((corners[corners.Count - 1].getFlags() & NavMeshQuery.DT_STRAIGHTPATH_END) != 0) ? true : false;
|
|
|
|
if (endOfPath)
|
|
|
|
return Math.Min(vDist2D(npos, corners[corners.Count - 1].getPos()), range);
|
|
|
|
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2023-03-28 19:52:26 +03:00
|
|
|
public Vector3f calcSmoothSteerDirection()
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-03-28 18:03:33 +03:00
|
|
|
Vector3f dir = new Vector3f();
|
2023-03-16 19:48:49 +03:00
|
|
|
if (0 < corners.Count)
|
|
|
|
{
|
|
|
|
int ip0 = 0;
|
|
|
|
int ip1 = Math.Min(1, corners.Count - 1);
|
2023-03-28 19:52:26 +03:00
|
|
|
var p0 = corners[ip0].getPos();
|
|
|
|
var p1 = corners[ip1].getPos();
|
2023-03-16 19:48:49 +03:00
|
|
|
|
2023-03-28 19:52:26 +03:00
|
|
|
var dir0 = vSub(p0, npos);
|
|
|
|
var dir1 = vSub(p1, npos);
|
2023-03-16 19:48:49 +03:00
|
|
|
dir0[1] = 0;
|
|
|
|
dir1[1] = 0;
|
|
|
|
|
|
|
|
float len0 = vLen(dir0);
|
|
|
|
float len1 = vLen(dir1);
|
|
|
|
if (len1 > 0.001f)
|
|
|
|
dir1 = vScale(dir1, 1.0f / len1);
|
|
|
|
|
|
|
|
dir[0] = dir0[0] - dir1[0] * len0 * 0.5f;
|
|
|
|
dir[1] = 0;
|
|
|
|
dir[2] = dir0[2] - dir1[2] * len0 * 0.5f;
|
|
|
|
|
2023-03-28 19:52:26 +03:00
|
|
|
vNormalize(ref dir);
|
2023-03-16 19:48:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
2023-03-28 19:52:26 +03:00
|
|
|
public Vector3f calcStraightSteerDirection()
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-03-28 18:03:33 +03:00
|
|
|
Vector3f dir = new Vector3f();
|
2023-03-16 19:48:49 +03:00
|
|
|
if (0 < corners.Count)
|
|
|
|
{
|
|
|
|
dir = vSub(corners[0].getPos(), npos);
|
|
|
|
dir[1] = 0;
|
2023-03-28 19:52:26 +03:00
|
|
|
vNormalize(ref dir);
|
2023-03-16 19:48:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
2023-03-28 19:52:26 +03:00
|
|
|
public void setTarget(long refs, Vector3f pos)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
|
|
|
targetRef = refs;
|
2023-03-28 19:52:26 +03:00
|
|
|
vCopy(ref targetPos, pos);
|
2023-03-16 19:48:49 +03:00
|
|
|
targetPathQueryResult = null;
|
|
|
|
if (targetRef != 0)
|
|
|
|
{
|
|
|
|
targetState = MoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
targetState = MoveRequestState.DT_CROWDAGENT_TARGET_FAILED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|