示例#1
0
/**
@par

This is the function used to plan local movement within the corridor. One or more corners can be 
detected in order to plan movement. It performs essentially the same function as #dtNavMeshQuery::findStraightPath.

Due to internal optimizations, the maximum number of corners returned will be (@p maxCorners - 1) 
For example: If the buffers are sized to hold 10 corners, the function will never return more than 9 corners. 
So if 10 corners are needed, the buffers should be sized for 11 corners.

If the target is within range, it will be the last corner and have a polygon reference id of zero.
*/
int dtPathCorridor::findCorners(float* cornerVerts, unsigned char* cornerFlags,
							  dtPolyRef* cornerPolys, const int maxCorners,
							  dtNavMeshQuery* navquery, const dtQueryFilter* filter,
							  float radius)
{
	dtAssert(m_path);
	dtAssert(m_npath);
	
	static const float MIN_TARGET_DIST = 0.01f;

	dtQueryResult result;
	navquery->findStraightPath(m_pos, m_target, m_path, m_npath, result);
	
	int ncorners = dtMin(result.size(), maxCorners);
	result.copyRefs(cornerPolys, maxCorners);
	result.copyFlags(cornerFlags, maxCorners);
	result.copyPos(cornerVerts, maxCorners);

	// Prune points in the beginning of the path which are too close.
	while (ncorners)
	{
		if ((cornerFlags[0] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
			dtVdist2DSqr(&cornerVerts[0], m_pos) > dtSqr(MIN_TARGET_DIST))
			break;
		ncorners--;
		if (ncorners)
		{
			memmove(cornerFlags, cornerFlags+1, sizeof(unsigned char)*ncorners);
			memmove(cornerPolys, cornerPolys+1, sizeof(dtPolyRef)*ncorners);
			memmove(cornerVerts, cornerVerts+3, sizeof(float)*3*ncorners);
		}
	}

	// Prune points after an off-mesh connection.
	for (int i = 0; i < ncorners; ++i)
	{
		if (cornerFlags[i] & DT_STRAIGHTPATH_OFFMESH_CONNECTION)
		{
			ncorners = i+1;
			break;
		}
	}
	
	// [UE4] Offset path points from corners
	const dtNavMesh* nav = navquery->getAttachedNavMesh();
	float v1[3], v2[3], dir[3];

	for (int i = 0; i < ncorners - 1; i++)
	{
		int fromIdx = 0;
		while (m_path[fromIdx] != cornerPolys[i] && fromIdx < m_npath)
		{
			fromIdx++;
		}

		if (m_path[fromIdx] != cornerPolys[i] || fromIdx == 0)
			continue;

		const dtMeshTile* tile0 = 0;
		const dtMeshTile* tile1 = 0;
		const dtPoly* poly0 = 0;
		const dtPoly* poly1 = 0;

		nav->getTileAndPolyByRefUnsafe(m_path[fromIdx - 1], &tile0, &poly0);
		nav->getTileAndPolyByRefUnsafe(m_path[fromIdx], &tile1, &poly1);

		if (tile0 != tile1)
			continue;

		float* corner = &cornerVerts[i * 3];

		unsigned char dummyT1, dummyT2;
		navquery->getPortalPoints(m_path[fromIdx - 1], m_path[fromIdx], v1, v2, dummyT1, dummyT2);

		const float edgeLen = dtVdist(v1, v2);
		if (edgeLen > 0.001f)
		{
			const float edgeOffset = dtMin(radius, edgeLen * 0.75f) / edgeLen;

			if (dtVequal(corner, v1))
			{
				dtVsub(dir, v2, v1);
				dtVmad(corner, corner, dir, edgeOffset);
			}
			else
			{
				dtVsub(dir, v1, v2);
				dtVmad(corner, corner, dir, edgeOffset);
			}
		}
	}

	return ncorners;
}
		crowd->update(0.5, 0);

		// The agent should not have moved
		dtVcopy(agt1NewPos, crowd->getAgent(ag.id)->position);	
		CHECK(dtVequal(agt1NewPos, posAgt1));

		// This time we affect the behavior with the right size
		CHECK(pipeline->setBehaviors(&behavior, 1));

		crowd->update(0.5, 0);

		dtVcopy(agt1NewPos, crowd->getAgent(ag.id)->position);	

		// A behavior has been affected to the pipeline, the agent should have moved
		CHECK(!dtVequal(agt1NewPos, posAgt1));

	}

	SECTION("Using a container", "Using a container to store behaviors, set them to the pipeline and then destroy the container. The behaviors should still be in the pipeline")
	{
		dtCollisionAvoidance* ca = dtCollisionAvoidance::allocate(crowd->getAgentCount());
		ca->init();

		dtCollisionAvoidanceParams* params = ca->getBehaviorParams(ag.id);

		if (params)
		{
			params->debug = 0;
			params->velBias = 0.4f;
			params->weightDesVel = 2.0f;
示例#3
0
void PathInfo::updateNextPosition()
{
    float x, y, z;

    getStartPosition(x, y, z);
    float startPos[3] = {y, z, x};
    getEndPosition(x, y, z);
    float endPos[3] = {y, z, x};

    float* pathPoints = new float[MAX_PATH_LENGTH*3];
    int pointCount = m_navMesh->findStraightPath(
        startPos,           // start position
        endPos,             // end position
        m_pathPolyRefs,     // current path
        m_length,           // lenth of current path
        pathPoints,         // [out] path corner points
        0,                  // [out] flags
        0,                  // [out] shortened path  PATHFIND TODO: see if this is usable (IE, doesn't leave gaps in path)
        MAX_PATH_LENGTH);   // maximum number of points/polygons to use

    // TODO: imitate PATHFIND_ITER code from RecastDemo so that terrain following is smoother

    if(pointCount == 0)
    {
        delete [] pathPoints;

        // only happens if pass bad data to findStraightPath or navmesh is broken
        sLog.outDebug("%u's UpdateNextPosition failed: 0 length path", m_sourceObject->GetGUID());
        shortcut();
        return;
    }

    int ix, iy, iz;
    if(pointCount == 1)
    {
        ix = 2; iy = 0; iz = 1;
    }
    else
    {
        ix = 5; iy = 3; iz = 4;
    }

    setNextPosition(pathPoints[ix], pathPoints[iy], pathPoints[iz]);

    // if startPosition == nextPosition, NPC will never advance to destination
    if(isSamePoint(m_startPosition, m_nextPosition) && !isSamePoint(m_nextPosition, m_endPosition))
        setNextPosition(pathPoints[ix + 3], pathPoints[iy + 3], pathPoints[iz + 3]);

    delete [] m_pathPoints;
    m_pathPoints = pathPoints;

    m_type = PathType(m_type | PATHFIND_NORMAL);

    // if end position from findStraightPath isn't the
    // place we want to go, there is likely no path
    endPos[0] = pathPoints[(pointCount-1)*3+2];
    endPos[1] = pathPoints[(pointCount-1)*3];
    endPos[2] = pathPoints[(pointCount-1)*3+1];
    if(!dtVequal(endPos, m_endPosition))
        m_type = PathType(m_type | PATHFIND_NOPATH);
}