Ejemplo n.º 1
0
ICmpObstruction::EFoundationCheck CCmpPathfinder::CheckBuildingPlacement(const IObstructionTestFilter& filter,
	entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w,
	entity_pos_t h, entity_id_t id, pass_class_t passClass, bool onlyCenterPoint)
{
	// Check unit obstruction
	CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
	if (!cmpObstructionManager)
		return ICmpObstruction::FOUNDATION_CHECK_FAIL_ERROR;

	if (cmpObstructionManager->TestStaticShape(filter, x, z, a, w, h, NULL))
		return ICmpObstruction::FOUNDATION_CHECK_FAIL_OBSTRUCTS_FOUNDATION;

	// Test against terrain:

	UpdateGrid();

	ICmpObstructionManager::ObstructionSquare square;
	CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), id);
	if (!cmpObstruction || !cmpObstruction->GetObstructionSquare(square))
		return ICmpObstruction::FOUNDATION_CHECK_FAIL_NO_OBSTRUCTION;

	if (onlyCenterPoint)
	{
		u16 i, j;
		NearestTile(x, z, i, j);

		if (IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass))
			return ICmpObstruction::FOUNDATION_CHECK_SUCCESS;

		return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS;
	}

	// Expand bounds by 1/sqrt(2) tile (multiply by TERRAIN_TILE_SIZE since we want world coordinates)
	entity_pos_t expand = entity_pos_t::FromInt(2).Sqrt().Multiply(entity_pos_t::FromInt(TERRAIN_TILE_SIZE / 2));
	CFixedVector2D halfSize(square.hw + expand, square.hh + expand);
	CFixedVector2D halfBound = Geometry::GetHalfBoundingBox(square.u, square.v, halfSize);

	u16 i0, j0, i1, j1;
	NearestTile(square.x - halfBound.X, square.z - halfBound.Y, i0, j0);
	NearestTile(square.x + halfBound.X, square.z + halfBound.Y, i1, j1);
	for (u16 j = j0; j <= j1; ++j)
	{
		for (u16 i = i0; i <= i1; ++i)
		{
			entity_pos_t x, z;
			TileCenter(i, j, x, z);
			if (Geometry::PointIsInSquare(CFixedVector2D(x - square.x, z - square.z), square.u, square.v, halfSize)
				&& !IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass))
			{
				return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS;
			}
		}
	}

	return ICmpObstruction::FOUNDATION_CHECK_SUCCESS;
}
Ejemplo n.º 2
0
bool CCmpPathfinder::CheckUnitPlacement(const IObstructionTestFilter& filter,
	entity_pos_t x, entity_pos_t z, entity_pos_t r,	pass_class_t passClass)
{
	// Check unit obstruction
	CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
	if (cmpObstructionManager.null())
		return false;

	if (cmpObstructionManager->TestUnitShape(filter, x, z, r, NULL))
		return false;

	// Test against terrain:

	UpdateGrid();

	u16 i0, j0, i1, j1;
	NearestTile(x - r, z - r, i0, j0);
	NearestTile(x + r, z + r, i1, j1);
	for (u16 j = j0; j <= j1; ++j)
	{
		for (u16 i = i0; i <= i1; ++i)
		{
			if (!IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass))
			{
				return false;
			}
		}
	}
	return true;
}
Ejemplo n.º 3
0
ICmpObstruction::EFoundationCheck CCmpPathfinder::CheckUnitPlacement(const IObstructionTestFilter& filter,
	entity_pos_t x, entity_pos_t z, entity_pos_t r,	pass_class_t passClass, bool onlyCenterPoint)
{
	// Check unit obstruction
	CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
	if (!cmpObstructionManager)
		return ICmpObstruction::FOUNDATION_CHECK_FAIL_ERROR;

	if (cmpObstructionManager->TestUnitShape(filter, x, z, r, NULL))
		return ICmpObstruction::FOUNDATION_CHECK_FAIL_OBSTRUCTS_FOUNDATION;

	// Test against terrain:

	UpdateGrid();
	
	if (onlyCenterPoint)
	{
		u16 i, j;
		NearestTile(x , z, i, j);

		if (IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass))
			return ICmpObstruction::FOUNDATION_CHECK_SUCCESS;

		return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS;
	}

	u16 i0, j0, i1, j1;
	NearestTile(x - r, z - r, i0, j0);
	NearestTile(x + r, z + r, i1, j1);
	for (u16 j = j0; j <= j1; ++j)
	{
		for (u16 i = i0; i <= i1; ++i)
		{
			if (!IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass))
			{
				return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS;
			}
		}
	}
	return ICmpObstruction::FOUNDATION_CHECK_SUCCESS;
}
Ejemplo n.º 4
0
static void AddTerrainEdges(std::vector<Edge>& edgesAA, std::vector<Vertex>& vertexes,
	u16 i0, u16 j0, u16 i1, u16 j1, fixed r,
	ICmpPathfinder::pass_class_t passClass, const Grid<TerrainTile>& terrain)
{
	PROFILE("AddTerrainEdges");

	std::vector<TileEdge> tileEdges;

	// Find all edges between tiles of differently passability statuses
	for (u16 j = j0; j <= j1; ++j)
	{
		for (u16 i = i0; i <= i1; ++i)
		{
			if (!IS_TERRAIN_PASSABLE(terrain.get(i, j), passClass))
			{
				bool any = false; // whether we're adding any edges of this tile

				if (j > 0 && IS_TERRAIN_PASSABLE(terrain.get(i, j-1), passClass))
				{
					TileEdge e = { i, j, TileEdge::BOTTOM };
					tileEdges.push_back(e);
					any = true;
				}

				if (j < terrain.m_H-1 && IS_TERRAIN_PASSABLE(terrain.get(i, j+1), passClass))
				{
					TileEdge e = { i, j, TileEdge::TOP };
					tileEdges.push_back(e);
					any = true;
				}

				if (i > 0 && IS_TERRAIN_PASSABLE(terrain.get(i-1, j), passClass))
				{
					TileEdge e = { i, j, TileEdge::LEFT };
					tileEdges.push_back(e);
					any = true;
				}

				if (i < terrain.m_W-1 && IS_TERRAIN_PASSABLE(terrain.get(i+1, j), passClass))
				{
					TileEdge e = { i, j, TileEdge::RIGHT };
					tileEdges.push_back(e);
					any = true;
				}

				// If we want to add any edge, then add the whole square to the axis-aligned-edges list.
				// (The inner edges are redundant but it's easier than trying to split the squares apart.)
				if (any)
				{
					CFixedVector2D v0 = CFixedVector2D(fixed::FromInt(i * (int)CELL_SIZE) - r, fixed::FromInt(j * (int)CELL_SIZE) - r);
					CFixedVector2D v1 = CFixedVector2D(fixed::FromInt((i+1) * (int)CELL_SIZE) + r, fixed::FromInt((j+1) * (int)CELL_SIZE) + r);
					Edge e = { v0, v1 };
					edgesAA.push_back(e);
				}
			}
		}
	}

	// TODO: maybe we should precompute these terrain edges since they'll rarely change?

	// TODO: for efficiency (minimising the A* search space), we should coalesce adjoining edges

	// Add all the tile outer edges to the search vertex lists
	for (size_t n = 0; n < tileEdges.size(); ++n)
	{
		u16 i = tileEdges[n].i;
		u16 j = tileEdges[n].j;
		CFixedVector2D v0, v1;
		Vertex vert;
		vert.status = Vertex::UNEXPLORED;
		vert.quadOutward = QUADRANT_ALL;

		switch (tileEdges[n].dir)
		{
		case TileEdge::BOTTOM:
		{
			v0 = CFixedVector2D(fixed::FromInt(i * (int)CELL_SIZE) - r, fixed::FromInt(j * (int)CELL_SIZE) - r);
			v1 = CFixedVector2D(fixed::FromInt((i+1) * (int)CELL_SIZE) + r, fixed::FromInt(j * (int)CELL_SIZE) - r);
			vert.p.X = v0.X - EDGE_EXPAND_DELTA; vert.p.Y = v0.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TR; vertexes.push_back(vert);
			vert.p.X = v1.X + EDGE_EXPAND_DELTA; vert.p.Y = v1.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TL; vertexes.push_back(vert);
			break;
		}
		case TileEdge::TOP:
		{
			v0 = CFixedVector2D(fixed::FromInt((i+1) * (int)CELL_SIZE) + r, fixed::FromInt((j+1) * (int)CELL_SIZE) + r);
			v1 = CFixedVector2D(fixed::FromInt(i * (int)CELL_SIZE) - r, fixed::FromInt((j+1) * (int)CELL_SIZE) + r);
			vert.p.X = v0.X + EDGE_EXPAND_DELTA; vert.p.Y = v0.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BL; vertexes.push_back(vert);
			vert.p.X = v1.X - EDGE_EXPAND_DELTA; vert.p.Y = v1.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BR; vertexes.push_back(vert);
			break;
		}
		case TileEdge::LEFT:
		{
			v0 = CFixedVector2D(fixed::FromInt(i * (int)CELL_SIZE) - r, fixed::FromInt((j+1) * (int)CELL_SIZE) + r);
			v1 = CFixedVector2D(fixed::FromInt(i * (int)CELL_SIZE) - r, fixed::FromInt(j * (int)CELL_SIZE) - r);
			vert.p.X = v0.X - EDGE_EXPAND_DELTA; vert.p.Y = v0.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BR; vertexes.push_back(vert);
			vert.p.X = v1.X - EDGE_EXPAND_DELTA; vert.p.Y = v1.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TR; vertexes.push_back(vert);
			break;
		}
		case TileEdge::RIGHT:
		{
			v0 = CFixedVector2D(fixed::FromInt((i+1) * (int)CELL_SIZE) + r, fixed::FromInt(j * (int)CELL_SIZE) - r);
			v1 = CFixedVector2D(fixed::FromInt((i+1) * (int)CELL_SIZE) + r, fixed::FromInt((j+1) * (int)CELL_SIZE) + r);
			vert.p.X = v0.X + EDGE_EXPAND_DELTA; vert.p.Y = v0.Y - EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_TL; vertexes.push_back(vert);
			vert.p.X = v1.X + EDGE_EXPAND_DELTA; vert.p.Y = v1.Y + EDGE_EXPAND_DELTA; vert.quadInward = QUADRANT_BL; vertexes.push_back(vert);
			break;
		}
		}
	}
}