Derive native drag fixtures from selectable integer pointer input
This commit is contained in:
@@ -61,7 +61,8 @@ namespace MagnetismHeroes.Tests
|
||||
{
|
||||
public string name, ballId, kind = "boundary";
|
||||
public FreePlayState source, expected;
|
||||
public Vector3 requested;
|
||||
public Vector3 requested, grabOffset, pointerDelta;
|
||||
public string firstHitId;
|
||||
public Vector2 start, end;
|
||||
}
|
||||
private Store _store;
|
||||
@@ -139,6 +140,60 @@ namespace MagnetismHeroes.Tests
|
||||
}
|
||||
[UnityTearDown] public IEnumerator TearDown() { Object.Destroy(_app.gameObject); yield return null; }
|
||||
|
||||
private Vector2 NativePoint(Vector3 world)
|
||||
{
|
||||
var viewport = _app.Orbit.Camera.WorldToViewportPoint(world);
|
||||
return new Vector2((float)Math.Round(viewport.x * 2400), (float)Math.Round((1 - viewport.y) * 1080));
|
||||
}
|
||||
private Vector2 PlayerPoint(Vector2 native) => _app.Orbit.Camera.ViewportToScreenPoint(new Vector3(native.x / 2400, 1 - native.y / 1080));
|
||||
private NativeDrag ExerciseNativeDrag(string name, string kind, FreePlayState source, Vector3 requested)
|
||||
{
|
||||
var id = source.balls[0].id; var origin = BoardPresenter.ToVector(source.balls[0].position);
|
||||
Assert.That(JsonUtility.ToJson(_app.Session.Camera), Is.EqualTo(JsonUtility.ToJson(source.camera)), "Exported camera must be the actual confirmed manual pose.");
|
||||
Assert.That(JsonUtility.ToJson(_app.Orbit.Snapshot()), Is.EqualTo(JsonUtility.ToJson(source.camera)));
|
||||
Assert.That(JsonUtility.ToJson(_app.Session.Board.ToFreePlayState(_app.Session.Camera)), Is.EqualTo(JsonUtility.ToJson(source)), "Entry must preserve every fixture ID, position and group.");
|
||||
var start = NativePoint(origin); Physics.SyncTransforms();
|
||||
var ray = _app.Orbit.Camera.ScreenPointToRay(PlayerPoint(start));
|
||||
var nativeRay = _app.Orbit.Camera.ViewportPointToRay(new Vector3(start.x / 2400, 1 - start.y / 1080));
|
||||
Assert.That(Vector3.Distance(ray.origin, nativeRay.origin), Is.LessThan(.00001f));
|
||||
Assert.That(Vector3.Distance(ray.direction, nativeRay.direction), Is.LessThan(.00001f), "Editor pixelRect must preserve the same native viewport ray.");
|
||||
Assert.That(Physics.Raycast(ray, out var hit, 100), Is.True);
|
||||
Assert.That(hit.collider.TryGetComponent<BallView>(out var ball) ? ball.BallId : hit.collider.name, Is.EqualTo(id), name + " actual first hit must select the requested sphere.");
|
||||
var grabOffset = hit.point - origin;
|
||||
var end = NativePoint(origin + requested + grabOffset);
|
||||
foreach (var point in new[] { start, end })
|
||||
Assert.That(point.x >= 530 && point.x <= 1850 && point.y >= 280 && point.y <= 750, Is.True, name + " integer native pointer must stay in the phone world UI-safe region.");
|
||||
var plane = new Plane(_app.Orbit.Camera.transform.forward, hit.point);
|
||||
var endRay = _app.Orbit.Camera.ScreenPointToRay(PlayerPoint(end));
|
||||
Assert.That(plane.Raycast(ray, out var from), Is.True); Assert.That(plane.Raycast(endRay, out var to), Is.True);
|
||||
var pointerDelta = endRay.GetPoint(to) - ray.GetPoint(from);
|
||||
var saved = JsonUtility.ToJson(_store.Saved);
|
||||
_app.Input.Begin(PlayerPoint(start), false); _app.Input.Move(PlayerPoint(end));
|
||||
Assert.That(_app.Orbit.IsAssisting, Is.True, "Actual BoardInput must acquire and move this friend.");
|
||||
Assert.That(JsonUtility.ToJson(_store.Saved), Is.EqualTo(saved), "Preview and assistance cannot save intermediate state.");
|
||||
var actual = _app.Presenter.DropDelta; var merge = _app.Presenter.MergeCandidate;
|
||||
if (kind == "boundary") Assert.That(actual.magnitude, Is.InRange(1.19f, 1.21f), "Actual pointer must stop at the .5 sphere margin.");
|
||||
if (kind == "foliage-pass")
|
||||
{
|
||||
Assert.That(Vector3.Distance(actual, pointerDelta), Is.LessThan(.001f), "The entire actual integer-pointer movement through foliage must pass without clipping.");
|
||||
Assert.That(actual.x, Is.GreaterThan(3.9f));
|
||||
}
|
||||
if (kind == "thin-obstacle") { Assert.That(actual.x, Is.GreaterThan(.1f).And.LessThan(requested.x - 1)); Assert.That(merge, Is.Null); }
|
||||
if (kind == "two-plus-three") Assert.That(merge, Is.EqualTo("native-contact-target"));
|
||||
var preview = _app.Presenter.Balls.ToDictionary(pair => pair.Key, pair => pair.Value.transform.position);
|
||||
var members = source.groups.Single(group => group.ballIds.Contains(id)).ballIds;
|
||||
foreach (var value in source.balls)
|
||||
Assert.That(Vector3.Distance(preview[value.id], BoardPresenter.ToVector(value.position) + (members.Contains(value.id) ? actual : Vector3.zero)), Is.LessThan(.001f), "Only the whole grabbed group may translate; all relative offsets and other friends are preserved.");
|
||||
_app.Input.End(PlayerPoint(end));
|
||||
Assert.That(_app.Session.Board.Balls.Select(value => value.id), Is.EquivalentTo(source.balls.Select(value => value.id)));
|
||||
foreach (var value in _app.Session.Board.Balls) Assert.That(Vector3.Distance(BoardPresenter.ToVector(value.position), preview[value.id]), Is.LessThan(.001f), "Drop must equal the actual input preview for every ID.");
|
||||
Assert.That(JsonUtility.ToJson(_app.Session.Camera), Is.EqualTo(JsonUtility.ToJson(source.camera)));
|
||||
if (kind != "two-plus-three") Assert.That(_app.Session.Board.Groups.Select(group => JsonUtility.ToJson(group)), Is.EqualTo(source.groups.Select(group => JsonUtility.ToJson(group))));
|
||||
else Assert.That(_app.Session.Board.Groups.Single().ballIds, Is.EquivalentTo(source.balls.Select(value => value.id)));
|
||||
return new NativeDrag { name = name, kind = kind, ballId = id, source = source, requested = requested, start = start, end = end,
|
||||
grabOffset = grabOffset, pointerDelta = pointerDelta, firstHitId = ball.BallId, expected = _app.Session.Board.ToFreePlayState(_app.Orbit.Snapshot()) };
|
||||
}
|
||||
|
||||
[UnityTest] public IEnumerator ExportActualMainPlaygroundNativeBoundaryFixtures()
|
||||
{
|
||||
var stages = new System.Collections.Generic.List<NativeStage>();
|
||||
@@ -233,13 +288,8 @@ namespace MagnetismHeroes.Tests
|
||||
_store.Saved.latestFreePlay = source; _app.Initialize(_store); _app.ContinueFreePlay(); yield return null;
|
||||
_app.Orbit.Camera.aspect = 2400f / 1080;
|
||||
var requested = Vector3.zero; requested[axis] = sign * 3;
|
||||
var start = _app.Orbit.Camera.WorldToViewportPoint(points[0]); var end = _app.Orbit.Camera.WorldToViewportPoint(points[0] + requested);
|
||||
var actual = _app.Environment.ConstrainTranslation(points, requested, _app.Presenter.transform);
|
||||
Assert.That(actual.magnitude, Is.InRange(1.19f, 1.21f), "Actual boundary clipping must stop at the .5 sphere margin.");
|
||||
_app.CommitMove("native-drag-group", BoardPresenter.ToPosition(actual)); yield return null;
|
||||
drags.Add(new NativeDrag { name = "boundary-" + count + "-" + axis + "-" + sign, ballId = id, source = source,
|
||||
expected = _app.Session.Board.ToFreePlayState(_app.Orbit.Snapshot()), requested = requested,
|
||||
start = new Vector2(start.x * 2400, (1 - start.y) * 1080), end = new Vector2(end.x * 2400, (1 - end.y) * 1080) });
|
||||
drags.Add(ExerciseNativeDrag("boundary-" + count + "-" + axis + "-" + sign, "boundary", source, requested));
|
||||
yield return null;
|
||||
}
|
||||
_app.StartStage(1); yield return null; Physics.SyncTransforms();
|
||||
var arch = _app.Environment.GetComponentsInChildren<MeshCollider>().First(value => value.enabled && value.GetComponentsInParent<Transform>().Any(parent => parent.name.Contains("OpenStoneArch")));
|
||||
@@ -279,15 +329,22 @@ namespace MagnetismHeroes.Tests
|
||||
var source = new FreePlayState { sourceStageId = 1, camera = camera, balls = balls.ToArray(), groups = groups.ToArray() };
|
||||
_store.Saved.latestFreePlay = source; _app.Initialize(_store); _app.ContinueFreePlay(); yield return null;
|
||||
Assert.That(_app.Presenter.IsSafeBoard(_app.Session.Board), Is.True); _app.Orbit.Camera.aspect = 2400f / 1080;
|
||||
var start = _app.Orbit.Camera.WorldToViewportPoint(sourcePoint); var end = _app.Orbit.Camera.WorldToViewportPoint(sourcePoint + requested);
|
||||
_app.Presenter.PreviewGroup("native-contact-source", requested);
|
||||
var actual = _app.Presenter.DropDelta; var merge = _app.Presenter.MergeCandidate;
|
||||
if (kind == "foliage-pass") Assert.That(Vector3.Distance(actual, requested), Is.LessThan(.001f));
|
||||
if (kind == "thin-obstacle") { Assert.That(actual.x, Is.GreaterThan(.1f).And.LessThan(requested.x - 1)); Assert.That(merge, Is.Null); }
|
||||
if (kind == "two-plus-three") Assert.That(merge, Is.EqualTo("native-contact-target"));
|
||||
_app.CommitMove("native-contact-source", BoardPresenter.ToPosition(actual), merge); yield return null;
|
||||
drags.Add(new NativeDrag { name = kind, kind = kind, ballId = source.balls[0].id, source = source, expected = _app.Session.Board.ToFreePlayState(_app.Orbit.Snapshot()), requested = requested,
|
||||
start = new Vector2(start.x * 2400, (1 - start.y) * 1080), end = new Vector2(end.x * 2400, (1 - end.y) * 1080) });
|
||||
if (kind == "thin-obstacle")
|
||||
{
|
||||
bool visible = false;
|
||||
foreach (float pitch in new[] { 0f, 15f, 30f, 45f, 60f })
|
||||
{
|
||||
var rotation = Quaternion.Euler(pitch, 0, 0);
|
||||
camera.rotation = new Rotation4(rotation.x, rotation.y, rotation.z, rotation.w); _app.Orbit.Apply(camera);
|
||||
Physics.SyncTransforms(); var ray = _app.Orbit.Camera.ScreenPointToRay(PlayerPoint(NativePoint(sourcePoint)));
|
||||
if (!Physics.Raycast(ray, out var hit, 100) || !hit.collider.TryGetComponent<BallView>(out var ball) || ball.BallId != source.balls[0].id) continue;
|
||||
Assert.That(Quaternion.Angle(_app.Orbit.Camera.transform.rotation, rotation), Is.LessThan(.001f), "Chosen pitch must already be a valid manual pose.");
|
||||
source.camera = _app.Orbit.Snapshot(); _app.Session.CommitCamera(source.camera); visible = true; break;
|
||||
}
|
||||
Assert.That(visible, Is.True, "The same thin-arch source must have an actually selectable supported pitch.");
|
||||
}
|
||||
Capture(kind + "-native-pointer-source", "Actual Editor-selected first hit and preserved source; integer native pointer oracle, not Android pass", 2400, 1080);
|
||||
drags.Add(ExerciseNativeDrag(kind, kind, source, requested)); yield return null;
|
||||
}
|
||||
var directory = Environment.GetEnvironmentVariable("MAGNETISM_NATIVE_FIXTURES") ?? Path.GetFullPath("artifacts/verification/PlaygroundInteraction/NativeFixtures");
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
Reference in New Issue
Block a user