Esempio n. 1
0
ePathFinderStatus cPath::CalculationStep(cChunk & a_Chunk)
{
	m_Chunk = &a_Chunk;
	if (m_Status != ePathFinderStatus::CALCULATING)
	{
		return m_Status;
	}

	if (m_BadChunkFound)
	{
		FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND);
		return m_Status;
	}

	if (m_StepsLeft == 0)
	{
		AttemptToFindAlternative();
	}
	else
	{
		--m_StepsLeft;
		int i;
		for (i = 0; i < CALCULATIONS_PER_STEP; ++i)
		{
			if (StepOnce())  // StepOnce returns true when no more calculation is needed.
			{
				break;  // if we're here, m_Status must have changed either to PATH_FOUND or PATH_NOT_FOUND.
			}
		}

		m_Chunk = nullptr;
	}
	return m_Status;
}
Esempio n. 2
0
bool cPath::StepOnce()
{
	cPathCell * CurrentCell = OpenListPop();

	// Path not reachable.
	if (CurrentCell == nullptr)
	{
		AttemptToFindAlternative();
		return true;
	}

	// Path found.
	if (CurrentCell->m_Location == m_Destination)
	{
		BuildPath();
		FinishCalculation(ePathFinderStatus::PATH_FOUND);
		return true;
	}

	// Calculation not finished yet
	// Check if we have a new NearestPoint.
	if ((m_Destination - CurrentCell->m_Location).Length() < 5)
	{
		if (m_Rand.NextInt(4) == 0)
		{
			m_NearestPointToTarget = CurrentCell;
		}
	}
	else if (CurrentCell->m_H < m_NearestPointToTarget->m_H)
	{
		m_NearestPointToTarget = CurrentCell;
	}
	// process a currentCell by inspecting all neighbors.


	// Now we start checking adjacent cells.


	// If true, no need to do more checks in that direction
	bool DoneEast = false,
	DoneWest = false,
	DoneNorth = false,
	DoneSouth = false;

	// If true, we can walk in that direction without changing height
	// This is used for deciding if to calculate diagonals
	bool WalkableEast = false,
	WalkableWest = false,
	WalkableNorth = false,
	WalkableSouth = false;

	// If we can jump without hitting the ceiling
	if (BodyFitsIn(CurrentCell->m_Location + Vector3i(0, 1, 0), CurrentCell->m_Location))
	{
		// For ladder climbing
		ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, 0), CurrentCell, JUMP_G_COST);

		// Check east-up
		if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 1, 0), CurrentCell, JUMP_G_COST))
		{
			DoneEast = true;
		}

		// Check west-up
		if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 1, 0), CurrentCell, JUMP_G_COST))
		{
			DoneWest = true;
		}

		// Check north-up
		if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, -1), CurrentCell, JUMP_G_COST))
		{
			DoneNorth = true;
		}

		// Check south-up
		if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, 1), CurrentCell, JUMP_G_COST))
		{
			DoneSouth = true;
		}

	}


	// Check North, South, East, West at our own height or below. We are willing to jump up to 3 blocks down.


	if (!DoneEast)
	{
		for (int y = 0; y >= -3; --y)
		{
			if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, y, 0),  CurrentCell, NORMAL_G_COST))
			{
				DoneEast = true;
				if (y == 0)
				{
					WalkableEast = true;
				}
				break;
			}
		}
	}

	if (!DoneWest)
	{
		for (int y = 0; y >= -3; --y)
		{
			if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, y, 0),  CurrentCell, NORMAL_G_COST))
			{
				DoneWest = true;
				if (y == 0)
				{
					WalkableWest = true;
				}
				break;
			}
		}
	}

	if (!DoneSouth)
	{
		for (int y = 0; y >= -3; --y)
		{
			if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, y, 1),  CurrentCell, NORMAL_G_COST))
			{
				DoneWest = true;
				if (y == 0)
				{
					WalkableSouth = true;
				}
				break;
			}
		}
	}

	if (!DoneNorth)
	{
		for (int y = 0; y >= -3; --y)
		{
			if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, y, -1), CurrentCell, NORMAL_G_COST))
			{
				DoneNorth = true;
				if (y == 0)
				{
					WalkableNorth = true;
				}
				break;
			}
		}
	}

	// Check diagonals

	if (WalkableNorth && WalkableEast)
	{
		ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, -1), CurrentCell, DIAGONAL_G_COST);
	}
	if (WalkableNorth && WalkableWest)
	{
		ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, -1), CurrentCell, DIAGONAL_G_COST);
	}
	if (WalkableSouth && WalkableEast)
	{
		ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, 1), CurrentCell, DIAGONAL_G_COST);
	}
	if (WalkableSouth && WalkableWest)
	{
		ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, 1), CurrentCell, DIAGONAL_G_COST);
	}

	return false;
}
Esempio n. 3
0
bool cPath::StepOnce()
{
	cPathCell * CurrentCell = OpenListPop();

	// Path not reachable.
	if (CurrentCell == nullptr)
	{
		AttemptToFindAlternative();
		return true;
	}

	// Path found.
	if (CurrentCell->m_Location == m_Destination)
	{
		BuildPath();
		FinishCalculation(ePathFinderStatus::PATH_FOUND);
		return true;
	}

	// Calculation not finished yet.
	// Check if we have a new NearestPoint.
	// TODO I don't like this that much, there should be a smarter way.
	if ((m_Destination - CurrentCell->m_Location).Length() < 5)
	{
		if (m_Rand.NextInt(4) == 0)
		{
			m_NearestPointToTarget = CurrentCell;
		}
	}
	else if (CurrentCell->m_H < m_NearestPointToTarget->m_H)
	{
		m_NearestPointToTarget = CurrentCell;
	}
	// process a currentCell by inspecting all neighbors.


	// Check North, South, East, West on our height.
	ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, 0),  CurrentCell, 10);
	ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, 0), CurrentCell, 10);
	ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 0, 1),  CurrentCell, 10);
	ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 0, -1), CurrentCell, 10);

	// Check diagonals on XY plane.
	// x = -1: west, x = 1: east.
	for (int x = -1; x <= 1; x += 2)
	{
		if (GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid)  // If there's a solid our east / west.
		{
			if (!GetCell(CurrentCell->m_Location + Vector3i(0, 1, 0))->m_IsSolid)  // If there isn't a solid above.
			{
				ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 1, 0), CurrentCell, JUMP_G_COST);  // Check east-up / west-up.
			}
		}
		else
		{
			ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, -1, 0), CurrentCell, 14);  // Else check east-down / west-down.
		}
	}

	// Check diagonals on the YZ plane.
	for (int z = -1; z <= 1; z += 2)
	{
		if (GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid)  // If there's a solid our north / south.
		{
			if (!GetCell(CurrentCell->m_Location + Vector3i(0, 1, 0))->m_IsSolid)  // If there isn't a solid above.
			{
				ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, z), CurrentCell, JUMP_G_COST);  // Check north-up / south-up.
			}
		}
		else
		{
			ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, -1, z), CurrentCell, 14);  // Else check north-down / south-down.
		}
	}

	// Check diagonals on the XZ plane. (Normal diagonals, this plane is special because of gravity, etc)
	for (int x = -1; x <= 1; x += 2)
	{
		for (int z = -1; z <= 1; z += 2)
		{
			// This condition prevents diagonal corner cutting.
			if (!GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid && !GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid)
			{
				// This prevents falling of "sharp turns" e.g. a 1x1x20 rectangle in the air which breaks in a right angle suddenly.
				if (GetCell(CurrentCell->m_Location + Vector3i(x, -1, 0))->m_IsSolid && GetCell(CurrentCell->m_Location + Vector3i(0, -1, z))->m_IsSolid)
				{
					ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 0, z), CurrentCell, 14);  // 14 is a good enough approximation of sqrt(10 + 10).
				}
			}
		}
	}

	return false;
}