Changes shore definition to distance on land (all water included) for better dock placement.

Updates build passability classes.
Fixes tile expansion in CheckBuildingPlacement (don't use FromFloat).
Changes dock rotation snapping to search outward.

This was SVN commit r10007.
This commit is contained in:
historic_bruno 2011-08-14 23:36:13 +00:00
parent 132f9bd63b
commit 1b8471da1f
4 changed files with 111 additions and 77 deletions

View File

@ -563,7 +563,11 @@ function handleInputBeforeGui(ev, hoveredObject)
"z": placementPosition.z
});
if (snapData)
{
placementAngle = snapData.angle;
placementPosition.x = snapData.x;
placementPosition.z = snapData.z;
}
updateBuildingPlacementPreview();
break;
@ -825,7 +829,11 @@ function handleInputAfterGui(ev)
"z": placementPosition.z
});
if (snapData)
{
placementAngle = snapData.angle;
placementPosition.x = snapData.x;
placementPosition.z = snapData.z;
}
updateBuildingPlacementPreview();

View File

@ -525,55 +525,66 @@ GuiInterface.prototype.GetFoundationSnapData = function(player, data)
halfSize = template.Footprint.Circle["@radius"];
}
// Find direction of most open water, algorithm:
// 1. Pick points in a circle around dock
// 2. If point is in water, add to array
// 3. Scan array looking for consective points
// 4. Find longest sequence of conseuctive points
// 5. Calculate angle using average of sequence
/* Find direction of most open water, algorithm:
* 1. Pick points in a circle around dock
* 2. If point is in water, add to array
* 3. Scan array looking for consective points
* 4. Find longest sequence of conseuctive points
* 5. If sequence equals all points, no direction can be determined,
* expand search outward and try (1) again
* 6. Calculate angle using average of sequence
*/
const numPoints = 16;
var waterPoints = [];
for (var i = 0; i < numPoints; ++i)
for (var dist = 0; dist < 4; ++dist)
{
var angle = (i/numPoints)*2*Math.PI;
var nx = data.x - halfSize*Math.sin(angle);
var nz = data.z + halfSize*Math.cos(angle);
if (cmpTerrain.GetGroundLevel(nx, nz) < cmpWaterManager.GetWaterLevel(nx, nz))
var waterPoints = [];
for (var i = 0; i < numPoints; ++i)
{
waterPoints.push(i);
var angle = (i/numPoints)*2*Math.PI;
var d = halfSize*(dist+1);
var nx = data.x - d*Math.sin(angle);
var nz = data.z + d*Math.cos(angle);
if (cmpTerrain.GetGroundLevel(nx, nz) < cmpWaterManager.GetWaterLevel(nx, nz))
{
waterPoints.push(i);
}
}
}
var consec = [];
var length = waterPoints.length;
for (var i = 0; i < length; ++i)
{
var consec = [];
var length = waterPoints.length;
for (var i = 0; i < length; ++i)
{
var count = 0;
for (var j = 0; j < (length-1); ++j)
{
if (((waterPoints[(i + j) % length]+1) % numPoints) == waterPoints[(i + j + 1) % length])
{
++count;
}
else
{
break;
}
}
consec[i] = count;
}
var start = 0;
var count = 0;
for (var j = 0; j < (length-1); ++j)
for (var c in consec)
{
if (((waterPoints[(i + j) % length]+1) % numPoints) == waterPoints[(i + j + 1) % length])
if (consec[c] > count)
{
++count;
}
else
{
break;
start = c;
count = consec[c];
}
}
consec[i] = count;
}
var start = 0;
var count = 0;
for (var c in consec)
{
if (consec[c] > count)
// If we've found a shoreline, stop searching
if (count != numPoints-1)
{
start = c;
count = consec[c];
return {"x": data.x, "z": data.z, "angle": -(((waterPoints[start] + consec[start]/2) % numPoints)/numPoints*2*Math.PI)};
}
}
return {"x": data.x, "z": data.z, "angle": -(((waterPoints[start] + consec[start]/2) % numPoints)/numPoints*2*Math.PI) };
}
return false;

View File

@ -23,12 +23,12 @@
-->
<building-land>
<MaxWaterDepth>0</MaxWaterDepth>
<MinShoreDistance>2.0</MinShoreDistance>
<MinShoreDistance>1.0</MinShoreDistance>
<MaxTerrainSlope>1.0</MaxTerrainSlope>
</building-land>
<building-shore>
<MaxShoreDistance>3.0</MaxShoreDistance>
<MaxTerrainSlope>1.5</MaxTerrainSlope>
<MaxShoreDistance>2.0</MaxShoreDistance>
<MaxTerrainSlope>1.25</MaxTerrainSlope>
</building-shore>
</PassabilityClasses>

View File

@ -399,44 +399,52 @@ void CCmpPathfinder::UpdateGrid()
for (u16 i = 0; i < m_MapSize; ++i)
{
// Find a land tile
if (!waterGrid.get(i, j) && (
(i > 0 && waterGrid.get(i-1, j)) || (i > 0 && j < m_MapSize-1 && waterGrid.get(i-1, j+1)) || (i > 0 && j > 0 && waterGrid.get(i-1, j-1)) ||
(i < m_MapSize-1 && waterGrid.get(i+1, j)) || (i < m_MapSize-1 && j < m_MapSize-1 && waterGrid.get(i+1, j+1)) || (i < m_MapSize-1 && j > 0 && waterGrid.get(i+1, j-1)) ||
(j > 0 && waterGrid.get(i, j-1)) || (j < m_MapSize-1 && waterGrid.get(i, j+1))
))
if (!waterGrid.get(i, j))
{
shoreGrid.set(i, j, 0);
}
else
{
shoreGrid.set(i, j, shoreMax);
if ((i > 0 && waterGrid.get(i-1, j)) || (i > 0 && j < m_MapSize-1 && waterGrid.get(i-1, j+1)) || (i > 0 && j > 0 && waterGrid.get(i-1, j-1))
|| (i < m_MapSize-1 && waterGrid.get(i+1, j)) || (i < m_MapSize-1 && j < m_MapSize-1 && waterGrid.get(i+1, j+1)) || (i < m_MapSize-1 && j > 0 && waterGrid.get(i+1, j-1))
|| (j > 0 && waterGrid.get(i, j-1)) || (j < m_MapSize-1 && waterGrid.get(i, j+1))
)
{ // If it's bordered by water, it's a shore tile
shoreGrid.set(i, j, 0);
}
else
{
shoreGrid.set(i, j, shoreMax);
}
}
}
}
// Expand influences to find shore distance
// Expand influences on land to find shore distance
for (size_t y = 0; y < m_MapSize; ++y)
{
u16 min = shoreMax;
for (size_t x = 0; x < m_MapSize; ++x)
{
u16 g = shoreGrid.get(x, y);
if (g > min)
shoreGrid.set(x, y, min);
else if (g < min)
min = g;
if (!waterGrid.get(x, y))
{
u16 g = shoreGrid.get(x, y);
if (g > min)
shoreGrid.set(x, y, min);
else if (g < min)
min = g;
++min;
++min;
}
}
for (size_t x = m_MapSize; x > 0; --x)
{
u16 g = shoreGrid.get(x-1, y);
if (g > min)
shoreGrid.set(x-1, y, min);
else if (g < min)
min = g;
if (!waterGrid.get(x-1, y))
{
u16 g = shoreGrid.get(x-1, y);
if (g > min)
shoreGrid.set(x-1, y, min);
else if (g < min)
min = g;
++min;
++min;
}
}
}
for (size_t x = 0; x < m_MapSize; ++x)
@ -444,23 +452,29 @@ void CCmpPathfinder::UpdateGrid()
u16 min = shoreMax;
for (size_t y = 0; y < m_MapSize; ++y)
{
u16 g = shoreGrid.get(x, y);
if (g > min)
shoreGrid.set(x, y, min);
else if (g < min)
min = g;
if (!waterGrid.get(x, y))
{
u16 g = shoreGrid.get(x, y);
if (g > min)
shoreGrid.set(x, y, min);
else if (g < min)
min = g;
++min;
++min;
}
}
for (size_t y = m_MapSize; y > 0; --y)
{
u16 g = shoreGrid.get(x, y-1);
if (g > min)
shoreGrid.set(x, y-1, min);
else if (g < min)
min = g;
if (!waterGrid.get(x, y-1))
{
u16 g = shoreGrid.get(x, y-1);
if (g > min)
shoreGrid.set(x, y-1, min);
else if (g < min)
min = g;
++min;
++min;
}
}
}
@ -698,8 +712,9 @@ bool CCmpPathfinder::CheckBuildingPlacement(const IObstructionTestFilter& filter
if (!cmpObstruction->GetObstructionSquare(square))
return false;
CFixedVector2D halfSize(square.hw, square.hh);
halfSize = halfSize * 1.41421f;
// Expand bounds by 1/sqrt(2) tile (multiply by CELL_SIZE since we want world coordinates)
entity_pos_t expand = entity_pos_t::FromInt(2).Sqrt().Multiply(entity_pos_t::FromInt(CELL_SIZE / 2));
CFixedVector2D halfSize(square.hw + expand, square.hh + expand);
CFixedVector2D halfBound = Geometry::GetHalfBoundingBox(square.u, square.v, halfSize);
u16 i0, j0, i1, j1;