diff --git a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs index 49381985f4..c6b6b3637c 100644 --- a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs +++ b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs @@ -68,8 +68,12 @@ namespace OpenRA.Graphics public void Update(CPos cell, Sprite sprite) { - var xyz = sprite == null ? float3.Zero : - worldRenderer.Screen3DPosition(map.CenterOfCell(cell)) + sprite.Offset - 0.5f * sprite.Size; + var xyz = float3.Zero; + if (sprite != null) + { + var cellOrigin = map.CenterOfCell(cell) - new WVec(0, 0, map.Grid.Ramps[map.Ramp[cell]].CenterHeightOffset); + xyz = worldRenderer.Screen3DPosition(cellOrigin) + sprite.Offset - 0.5f * sprite.Size; + } Update(cell.ToMPos(map.Grid.Type), sprite, xyz); } diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index 85aa1b8bf8..2ee520d341 100644 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -262,11 +262,9 @@ namespace OpenRA.Graphics var s = worldRenderer.ScreenPxPosition(p); if (Math.Abs(s.X - world.X) <= tileSize.Width && Math.Abs(s.Y - world.Y) <= tileSize.Height) { - var ramp = map.Ramp.Contains(uv) ? map.Ramp[uv] : 0; - var corners = map.Grid.Ramps[ramp].Corners; - var pos = map.CenterOfCell(uv.ToCPos(map)); - var screen = corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToArray(); - + var ramp = map.Grid.Ramps[map.Ramp.Contains(uv) ? map.Ramp[uv] : 0]; + var pos = map.CenterOfCell(uv.ToCPos(map)) - new WVec(0, 0, ramp.CenterHeightOffset); + var screen = ramp.Corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToArray(); if (screen.PolygonContains(world)) return uv.ToCPos(map); } diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 3b66521130..0302819fad 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -820,7 +820,7 @@ namespace OpenRA // (c) u, v coordinates run diagonally to the cell axes, and we define // 1024 as the length projected onto the primary cell axis // - 512 * sqrt(2) = 724 - var z = Height.Contains(cell) ? 724 * Height[cell] : 0; + var z = Height.Contains(cell) ? 724 * Height[cell] + Grid.Ramps[Ramp[cell]].CenterHeightOffset : 0; return new WPos(724 * (cell.X - cell.Y + 1), 724 * (cell.X + cell.Y + 1), z); } @@ -828,15 +828,39 @@ namespace OpenRA { var index = (int)subCell; if (index >= 0 && index < Grid.SubCellOffsets.Length) - return CenterOfCell(cell) + Grid.SubCellOffsets[index]; + { + var center = CenterOfCell(cell); + var offset = Grid.SubCellOffsets[index]; + var ramp = Ramp.Contains(cell) ? Ramp[cell] : 0; + if (ramp != 0) + { + var r = Grid.Ramps[ramp]; + offset += new WVec(0, 0, r.HeightOffset(offset.X, offset.Y) - r.CenterHeightOffset); + } + + return center + offset; + } + return CenterOfCell(cell); } public WDist DistanceAboveTerrain(WPos pos) { + if (Grid.Type == MapGridType.Rectangular) + return new WDist(pos.Z); + + // Apply ramp offset var cell = CellContaining(pos); - var delta = pos - CenterOfCell(cell); - return new WDist(delta.Z); + var offset = pos - CenterOfCell(cell); + + var ramp = Ramp[cell]; + if (ramp != 0) + { + var r = Grid.Ramps[ramp]; + return new WDist(offset.Z + r.CenterHeightOffset - r.HeightOffset(offset.X, offset.Y)); + } + + return new WDist(offset.Z); } public WVec Offset(CVec delta, int dz) diff --git a/OpenRA.Game/Map/MapGrid.cs b/OpenRA.Game/Map/MapGrid.cs index d52fc6a782..2e8483f153 100644 --- a/OpenRA.Game/Map/MapGrid.cs +++ b/OpenRA.Game/Map/MapGrid.cs @@ -24,6 +24,7 @@ namespace OpenRA public struct CellRamp { + public readonly int CenterHeightOffset; public readonly WVec[] Corners; public readonly WVec[][] Polygons; @@ -68,9 +69,13 @@ namespace OpenRA } else Polygons = new[] { Corners }; + + // Initial value must be asigned before HeightOffset can be called + CenterHeightOffset = 0; + CenterHeightOffset = HeightOffset(0, 0); } - public WDist DistanceAboveTerrain(WVec delta) + public int HeightOffset(int dX, int dY) { // Enumerate over the polygons, assuming that they are triangles // If the ramp is not split we will take the first three vertices of the corners as a valid triangle @@ -80,8 +85,8 @@ namespace OpenRA for (var i = 0; i < Polygons.Length; i++) { p = Polygons[i]; - u = ((p[1].Y - p[2].Y) * (delta.X - p[2].X) - (p[1].X - p[2].X) * (delta.Y - p[2].Y)) / 1024; - v = ((p[0].X - p[2].X) * (delta.Y - p[2].Y) - (p[0].Y - p[2].Y) * (delta.X - p[2].X)) / 1024; + u = ((p[1].Y - p[2].Y) * (dX - p[2].X) - (p[1].X - p[2].X) * (dY - p[2].Y)) / 1024; + v = ((p[0].X - p[2].X) * (dY - p[2].Y) - (p[0].Y - p[2].Y) * (dX - p[2].X)) / 1024; // Point is within the triangle if 0 <= u,v <= 1024 if (u >= 0 && u <= 1024 && v >= 0 && v <= 1024) @@ -89,8 +94,7 @@ namespace OpenRA } // Calculate w from u,v and interpolate height - var dz = (u * p[0].Z + v * p[1].Z + (1024 - u - v) * p[2].Z) / 1024; - return new WDist(delta.Z - dz); + return (u * p[0].Z + v * p[1].Z + (1024 - u - v) * p[2].Z) / 1024; } } diff --git a/OpenRA.Mods.Common/Activities/Move/Move.cs b/OpenRA.Mods.Common/Activities/Move/Move.cs index 5fb74f87ad..00757f93cc 100644 --- a/OpenRA.Mods.Common/Activities/Move/Move.cs +++ b/OpenRA.Mods.Common/Activities/Move/Move.cs @@ -464,6 +464,7 @@ namespace OpenRA.Mods.Common.Activities else pos = WPos.Lerp(From, To, moveFraction, MoveFractionTotal); + pos -= new WVec(WDist.Zero, WDist.Zero, self.World.Map.DistanceAboveTerrain(pos)); mobile.SetVisualPosition(self, pos); } else diff --git a/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs b/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs index 0396b55d10..370ee15c51 100644 --- a/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs +++ b/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs @@ -64,7 +64,7 @@ namespace OpenRA.Mods.Common.Traits var height = (int)map.Height[uv]; var r = map.Grid.Ramps[map.Ramp[uv]]; - var pos = map.CenterOfCell(uv.ToCPos(map)); + var pos = map.CenterOfCell(uv.ToCPos(map)) - new WVec(0, 0, r.CenterHeightOffset); var width = uv == mouseCell ? 3 : 1; // Colors change between points, so render separately