From fb5aae827a2b8194ce4eaff7b223a56056adea80 Mon Sep 17 00:00:00 2001 From: Gustas <37534529+PunkPun@users.noreply.github.com> Date: Thu, 31 Jul 2025 20:01:26 +0300 Subject: [PATCH] Fix MPos projection --- OpenRA.Game/CPos.cs | 12 +--- OpenRA.Test/OpenRA.Game/CoordinateTest.cs | 78 +++++++++++++++++++---- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/OpenRA.Game/CPos.cs b/OpenRA.Game/CPos.cs index 6715026e30..abb20128d1 100644 --- a/OpenRA.Game/CPos.cs +++ b/OpenRA.Game/CPos.cs @@ -78,17 +78,9 @@ namespace OpenRA return new MPos(X, Y); // Convert from RectangularIsometric cell (x, y) position to rectangular map position (u, v) - // - The staggered rows make this fiddly (hint: draw a diagram!) - // (a) Consider the relationships: - // - +1x (even -> odd) adds (0, 1) to (u, v) - // - +1x (odd -> even) adds (1, 1) to (u, v) - // - +1y (even -> odd) adds (-1, 1) to (u, v) - // - +1y (odd -> even) adds (0, 1) to (u, v) - // (b) Therefore: - // - ax + by adds (a - b)/2 to u (only even increments count) - // - ax + by adds a + b to v - var u = (X - Y) / 2; + // The staggered rows make this fiddly. var v = X + Y; + var u = (v - (v & 1)) / 2 - Y; return new MPos(u, v); } diff --git a/OpenRA.Test/OpenRA.Game/CoordinateTest.cs b/OpenRA.Test/OpenRA.Game/CoordinateTest.cs index 3856c1f139..d53af38fe2 100644 --- a/OpenRA.Test/OpenRA.Game/CoordinateTest.cs +++ b/OpenRA.Test/OpenRA.Game/CoordinateTest.cs @@ -10,6 +10,7 @@ #endregion using System; +using System.Linq; using NUnit.Framework; namespace OpenRA.Test @@ -17,25 +18,74 @@ namespace OpenRA.Test [TestFixture] public class CoordinateTest { - [TestCase(TestName = "Test CPos and MPos conversion and back again.")] - public void CoarseToMapProjection() + [TestCase(TestName = "Test CPos to MPos conversion and back again.")] + public void CPosConversionRoundtrip() { foreach (var gridType in Enum.GetValues()) { - for (var x = 0; x < 12; x++) - { - for (var y = 0; y < 12; y++) - { - var cell = new CPos(x, y); + var expected = new CellCoordsRegion(new CPos(-12, -12), new CPos(12, 12)); + var actual = expected.Select(pos => pos.ToMPos(gridType).ToCPos(gridType)).ToArray(); - // Known problem on isometric mods that shouldn't be visible to players as these are outside the map. - if (gridType == MapGridType.RectangularIsometric && y > x) - continue; - - Assert.That(cell, Is.EqualTo(cell.ToMPos(gridType).ToCPos(gridType))); - } - } + Assert.That(expected, Is.EqualTo(actual)); } } + + [TestCase(TestName = "Test MPos to CPos conversion and back again.")] + public void MPosConversionRoundtrip() + { + foreach (var gridType in Enum.GetValues()) + { + var expected = new MapCoordsRegion(new MPos(-12, -12), new MPos(12, 12)); + var actual = expected.Select(pos => pos.ToCPos(gridType).ToMPos(gridType)).ToArray(); + + Assert.That(expected, Is.EqualTo(actual)); + } + } + + [TestCase(TestName = "Test directional movement of ToCPos.")] + public void TestIsometricCPosConversion() + { + const MapGridType Isometric = MapGridType.RectangularIsometric; + Assert.That(new CPos(0, 0), Is.EqualTo(new MPos(0, 0).ToCPos(Isometric))); + + Assert.That(new CPos(1, 1), Is.EqualTo(new MPos(0, 2).ToCPos(Isometric))); + Assert.That(new CPos(2, 2), Is.EqualTo(new MPos(0, 4).ToCPos(Isometric))); + Assert.That(new CPos(3, 3), Is.EqualTo(new MPos(0, 6).ToCPos(Isometric))); + + Assert.That(new CPos(1, 0), Is.EqualTo(new MPos(0, 1).ToCPos(Isometric))); + Assert.That(new CPos(2, 0), Is.EqualTo(new MPos(1, 2).ToCPos(Isometric))); + Assert.That(new CPos(3, 0), Is.EqualTo(new MPos(1, 3).ToCPos(Isometric))); + + Assert.That(new CPos(0, 1), Is.EqualTo(new MPos(-1, 1).ToCPos(Isometric))); + Assert.That(new CPos(0, 2), Is.EqualTo(new MPos(-1, 2).ToCPos(Isometric))); + Assert.That(new CPos(0, 3), Is.EqualTo(new MPos(-2, 3).ToCPos(Isometric))); + + Assert.That(new CPos(1, -1), Is.EqualTo(new MPos(1, 0).ToCPos(Isometric))); + Assert.That(new CPos(2, -2), Is.EqualTo(new MPos(2, 0).ToCPos(Isometric))); + Assert.That(new CPos(3, -3), Is.EqualTo(new MPos(3, 0).ToCPos(Isometric))); + } + + [TestCase(TestName = "Test directional movement of ToMPos.")] + public void TestIsometricMPosConversion() + { + const MapGridType Isometric = MapGridType.RectangularIsometric; + Assert.That(new MPos(0, 0), Is.EqualTo(new CPos(0, 0).ToMPos(Isometric))); + + Assert.That(new MPos(0, 2), Is.EqualTo(new CPos(1, 1).ToMPos(Isometric))); + Assert.That(new MPos(0, 4), Is.EqualTo(new CPos(2, 2).ToMPos(Isometric))); + Assert.That(new MPos(0, 6), Is.EqualTo(new CPos(3, 3).ToMPos(Isometric))); + + Assert.That(new MPos(0, 1), Is.EqualTo(new CPos(1, 0).ToMPos(Isometric))); + Assert.That(new MPos(1, 2), Is.EqualTo(new CPos(2, 0).ToMPos(Isometric))); + Assert.That(new MPos(1, 3), Is.EqualTo(new CPos(3, 0).ToMPos(Isometric))); + + Assert.That(new MPos(-1, 1), Is.EqualTo(new CPos(0, 1).ToMPos(Isometric))); + Assert.That(new MPos(-1, 2), Is.EqualTo(new CPos(0, 2).ToMPos(Isometric))); + Assert.That(new MPos(-2, 3), Is.EqualTo(new CPos(0, 3).ToMPos(Isometric))); + + Assert.That(new MPos(1, 0), Is.EqualTo(new CPos(1, -1).ToMPos(Isometric))); + Assert.That(new MPos(2, 0), Is.EqualTo(new CPos(2, -2).ToMPos(Isometric))); + Assert.That(new MPos(3, 0), Is.EqualTo(new CPos(3, -3).ToMPos(Isometric))); + } } }