fix: keep friend numerals readable through camera rotation
This commit is contained in:
@@ -4,6 +4,8 @@ using System.Linq;
|
||||
using MagnetismHeroes.Core;
|
||||
using MagnetismHeroes.UnityRuntime.Bootstrap;
|
||||
using MagnetismHeroes.UnityRuntime.StageAssets;
|
||||
using MagnetismHeroes.UnityRuntime.Presentation;
|
||||
using TMPro;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
@@ -66,6 +68,46 @@ namespace MagnetismHeroes.Tests
|
||||
Drag(start, camera.WorldToScreenPoint(destination + offset));
|
||||
}
|
||||
|
||||
[UnityTest] public IEnumerator GroupNumberFrontViewStaysAboveAndVisible() => CheckGroupNumber(Quaternion.identity);
|
||||
[UnityTest] public IEnumerator GroupNumberBelowViewStaysAboveAndVisible() => CheckGroupNumber(Quaternion.Euler(-90, 0, 0));
|
||||
[UnityTest] public IEnumerator GroupNumberRolledViewStaysAboveAndVisible() => CheckGroupNumber(Quaternion.Euler(0, 0, 90));
|
||||
[UnityTest] public IEnumerator GroupNumberPreviewFollowsTheFriendWithoutChangingCommittedState() => CheckGroupNumber(Quaternion.Euler(-90, 0, 0), true);
|
||||
|
||||
private IEnumerator CheckGroupNumber(Quaternion rotation, bool preview = false)
|
||||
{
|
||||
_app.StartStage(1); yield return null;
|
||||
var state = _app.Session.Board.Balls.Single();
|
||||
_app.CommitMove(_app.Session.Board.Groups.Single().id, new Position3(4 - state.position.x, 0, 0));
|
||||
_app.CountBall(state.id); Assert.That(_app.Session.Screen, Is.EqualTo(SessionScreen.FreePlay));
|
||||
var saved = JsonUtility.ToJson(_store.Saved); var position = _app.Session.Board.Balls.Single().position;
|
||||
var committedCamera = JsonUtility.ToJson(_app.Session.Camera);
|
||||
_app.Orbit.Apply(new CameraState { target = new Position3(4, 0.6f, 0), distance = 8,
|
||||
rotation = new Rotation4(rotation.x, rotation.y, rotation.z, rotation.w) });
|
||||
if (preview) _app.Presenter.PreviewGroup(_app.Session.Board.Groups.Single().id, new Vector3(0.8f, 0, 0.3f));
|
||||
yield return null; Physics.SyncTransforms();
|
||||
var camera = _app.Presenter.Camera; var badge = _app.Presenter.GetComponentInChildren<GroupBadge>();
|
||||
var number = badge.GetComponentInChildren<TextMeshPro>(); number.ForceMeshUpdate();
|
||||
Assert.That(number.text, Is.EqualTo("1")); Assert.That(number.textInfo.characterInfo[0].isVisible, Is.True);
|
||||
Assert.That(Vector3.Dot(number.transform.forward, camera.transform.forward), Is.EqualTo(1).Within(0.001));
|
||||
Assert.That(Vector3.Dot(badge.transform.Find("RepresentativeFace").forward, camera.transform.forward), Is.EqualTo(1).Within(0.001));
|
||||
var glyph = number.textInfo.characterInfo[0];
|
||||
var glyphWorld = new[] { glyph.bottomLeft, glyph.topLeft, glyph.topRight, glyph.bottomRight }.Select(number.transform.TransformPoint).ToArray();
|
||||
var glyphScreen = glyphWorld.Select(camera.WorldToScreenPoint).ToArray();
|
||||
Assert.That(glyphScreen.All(point => point.z > camera.nearClipPlane && point.x > 0 && point.x < Screen.width && point.y > 0 && point.y < Screen.height), Is.True);
|
||||
var ballBounds = _app.Presenter.Balls.Values.Single().GetComponent<SphereCollider>().bounds;
|
||||
float ballTop = float.NegativeInfinity;
|
||||
foreach (int x in new[] { -1, 1 }) foreach (int y in new[] { -1, 1 }) foreach (int z in new[] { -1, 1 })
|
||||
ballTop = Mathf.Max(ballTop, camera.WorldToScreenPoint(ballBounds.center + Vector3.Scale(ballBounds.extents, new Vector3(x, y, z))).y);
|
||||
Assert.That(glyphScreen.Min(point => point.y), Is.GreaterThan(ballTop), "The visible glyph must sit above the sphere in the current camera view.");
|
||||
var glyphCenter = glyphWorld.Aggregate(Vector3.zero, (sum, vertex) => sum + vertex) / glyphWorld.Length;
|
||||
var ray = camera.ScreenPointToRay(camera.WorldToScreenPoint(glyphCenter));
|
||||
Assert.That(Physics.Raycast(ray, Vector3.Distance(ray.origin, glyphCenter)), Is.False, "Scene colliders must not hide the number before its glyph plane.");
|
||||
Assert.That(_app.Session.Board.Balls.Single().position, Is.EqualTo(position));
|
||||
Assert.That(JsonUtility.ToJson(_app.Session.Camera), Is.EqualTo(committedCamera)); Assert.That(JsonUtility.ToJson(_store.Saved), Is.EqualTo(saved));
|
||||
_app.Presenter.CancelPreview();
|
||||
Assert.That(_app.Presenter.Balls.Values.Single().transform.position, Is.EqualTo(new Vector3(position.x, position.y, position.z)));
|
||||
}
|
||||
|
||||
[UnityTest] public IEnumerator PinchReleaseOutsideRestoresCameraAndSuppressesRemainingTouch()
|
||||
{
|
||||
_touchscreen = InputSystem.AddDevice<Touchscreen>(); _app.StartStage(1); yield return null; Physics.SyncTransforms();
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace MagnetismHeroes.UnityRuntime.Presentation
|
||||
var group = groups[index];
|
||||
var center = group.ballIds.Select(id => _balls[id].transform.position).Aggregate(Vector3.zero, (sum, value) => sum + value) / group.ballIds.Length;
|
||||
var representative = _balls[group.ballIds[0]].transform.position;
|
||||
_badges[index].Bind(group.ballIds.Length, center + Vector3.up * 0.95f,
|
||||
_badges[index].Bind(group.ballIds.Length, center + _camera.transform.up * 0.95f,
|
||||
representative - _camera.transform.forward * 0.49f);
|
||||
_badges[index].FaceCamera(_camera);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user