Advance blocked split previews to the last safe Core delta
This commit is contained in:
@@ -182,11 +182,15 @@ namespace MagnetismHeroes.Tests
|
||||
Assert.That(_app.Presenter.CanDropGroup("group-0"), Is.True);
|
||||
var validDelta = _app.Presenter.DropDelta; var validPoint = _app.Presenter.Balls["safety-2"].transform.position;
|
||||
_app.Input.Move(point + new Vector2(140, 0));
|
||||
Assert.That(_app.Presenter.DropDelta, Is.EqualTo(validDelta));
|
||||
Assert.That(_app.Presenter.Balls["safety-2"].transform.position, Is.EqualTo(validPoint));
|
||||
var stopped = _app.Presenter.Balls["safety-2"].transform.position;
|
||||
Assert.That(stopped.x, Is.GreaterThan(validPoint.x + .2f), "Continue the safe part of the split drag up to the obstacle.");
|
||||
Assert.That(stopped.x, Is.EqualTo(.689f).Within(.003f), "The whole unit sphere must stop just before the thin wall.");
|
||||
Assert.That(_app.Presenter.DropDelta.x, Is.GreaterThan(validDelta.x + .2f));
|
||||
var corePreview = _app.Session.Board.PreviewSplit("group-0", new[] { "safety-2" }, BoardPresenter.ToPosition(_app.Presenter.DropDelta));
|
||||
foreach (var ball in corePreview) Assert.That(_app.Presenter.Balls[ball.id].transform.position, Is.EqualTo(BoardPresenter.ToVector(ball.position)));
|
||||
_app.Input.Move(point + new Vector2(128, 0));
|
||||
var reverse = _app.Presenter.Balls["safety-2"].transform.position;
|
||||
Assert.That(reverse.x, Is.LessThan(validPoint.x - .01f));
|
||||
Assert.That(reverse.x, Is.LessThan(stopped.x - .01f), "Reverse must act immediately at the last safe split delta.");
|
||||
var preview = _app.Presenter.Balls.ToDictionary(pair => pair.Key, pair => pair.Value.transform.position);
|
||||
_app.Input.End(point + new Vector2(128, 0)); yield return null;
|
||||
Assert.That(_app.Session.Board.Groups.Length, Is.EqualTo(2));
|
||||
|
||||
@@ -144,20 +144,40 @@ namespace MagnetismHeroes.UnityRuntime.Presentation
|
||||
CancelPreview(); _previewGroup = groupId; _splitPreview = true; _previewValid = false;
|
||||
return false;
|
||||
}
|
||||
if (!CanSweepSplit(positions, selected))
|
||||
{
|
||||
if (!hadValidPreview) { _previewValid = false; return false; }
|
||||
// Search Core input deltas, so the last safe arrays and the committed delta stay identical.
|
||||
var previousDelta = DropDelta;
|
||||
positions = _board.PreviewSplit(groupId, selected, ToPosition(previousDelta));
|
||||
float safe = 0, blocked = 1;
|
||||
for (int iteration = 0; iteration < 20; iteration++)
|
||||
{
|
||||
float fraction = (safe + blocked) * .5f;
|
||||
var candidateDelta = Vector3.Lerp(previousDelta, delta, fraction);
|
||||
var candidate = _board.PreviewSplit(groupId, selected, ToPosition(candidateDelta));
|
||||
if (candidate != null && candidate.All(ball => _environment.IsSafeSphere(ToVector(ball.position), transform))
|
||||
&& CanSweepSplit(candidate, selected))
|
||||
{ safe = fraction; positions = candidate; }
|
||||
else blocked = fraction;
|
||||
}
|
||||
delta = Vector3.Lerp(previousDelta, delta, safe);
|
||||
}
|
||||
foreach (var ball in positions) _balls[ball.id].transform.position = ToVector(ball.position);
|
||||
DropDelta = delta; _previewValid = true;
|
||||
PositionBadges(); return true;
|
||||
}
|
||||
|
||||
private bool CanSweepSplit(IReadOnlyList<BallState> positions, IReadOnlyList<string> selected)
|
||||
{
|
||||
foreach (var ball in positions.Where(ball => selected.Contains(ball.id)))
|
||||
{
|
||||
var start = _balls[ball.id].transform.position;
|
||||
var movement = ToVector(ball.position) - start;
|
||||
if ((_environment.ConstrainTranslation(new[] { start }, movement, transform) - movement).sqrMagnitude > .00000001f)
|
||||
{
|
||||
// Keep exactly the last Core-produced split and its input delta; never commit a clipped shape.
|
||||
_previewValid = hadValidPreview;
|
||||
return hadValidPreview;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach (var ball in positions) _balls[ball.id].transform.position = ToVector(ball.position);
|
||||
DropDelta = delta; _previewValid = true;
|
||||
PositionBadges(); return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ShowSelection(IReadOnlyCollection<string> selected)
|
||||
|
||||
Reference in New Issue
Block a user