Belt rocks and their reticle are drawn on the floater layer over the field by DrawAhead
DrawAhead.Chunk/ChunkHeight (ruling asteroids-on-floater-layer); ZoneRenderer and the chunk reticle both read it; ChunkWorldPosition and the renderer's global are gone. Fixes the reticle sitting off the rock by |field|. Test: AChunkIsDrawnOnTheFloaterLayerOverTheField. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
2055e18d3e
commit
71fa9411c6
4 changed files with 40 additions and 13 deletions
|
|
@ -1174,15 +1174,6 @@ public class ActionGameManager : MonoBehaviour
|
|||
}
|
||||
}
|
||||
|
||||
// A chunk's pose is planar (Zone.ChunkPose), read at the drawn time so the reticle sits on the drawn rock; the renderer
|
||||
// draws it at the asteroid layer's height.
|
||||
private float3 ChunkWorldPosition(ChunkId chunk)
|
||||
{
|
||||
var zone = CurrentEntity.Zone;
|
||||
var pose = zone.ChunkPose(chunk.Field, chunk.Index, DrawAhead.Time(zone, Clock.Lead));
|
||||
return float3(pose.x, Settings.PlanetSettings.AsteroidVerticalOffset, pose.y);
|
||||
}
|
||||
|
||||
// The one way a run ends, won or lost: the run is cleared and the main menu returns.
|
||||
private void EndRun()
|
||||
{
|
||||
|
|
@ -1465,7 +1456,7 @@ public class ActionGameManager : MonoBehaviour
|
|||
ViewDot.Target = ZoneRenderer.EntityInstances[CurrentEntity].LookAtPoint.position;
|
||||
var target = CurrentEntity.Target.Value;
|
||||
if (target.Chunk is ChunkId chunk)
|
||||
TargetIndicator.Target = ChunkWorldPosition(chunk).ToUnity();
|
||||
TargetIndicator.Target = DrawAhead.Chunk(CurrentEntity.Zone, Settings.GameplaySettings, chunk, lead).ToUnity();
|
||||
else if (target.Entity != null)
|
||||
TargetIndicator.Target = DrawAhead.Position(target.Entity, lead).ToUnity();
|
||||
var distance = length(ViewDot.Target.ToCultMath() - ownDrawn);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,16 @@ public static class DrawAhead
|
|||
// The drawn height of a floater (loot, mines): the field at the drawn time plus the floater layer.
|
||||
public static float FloaterHeight(Zone zone, GameplaySettings settings, float2 planar, float lead) => Height(zone, planar, lead) + settings.FloaterLayerHeight;
|
||||
|
||||
// A belt rock's drawn position (ruling asteroids-on-floater-layer): its planar pose at the drawn time, on the floater layer over the field.
|
||||
// Open question asteroid-clearance: the rock centre sits at the layer. ChunkHeight is the one line that changes if its top should (pose.w is the radius).
|
||||
public static float ChunkHeight(Zone zone, GameplaySettings settings, float4 pose, float lead) => FloaterHeight(zone, settings, pose.xy, lead);
|
||||
|
||||
public static float3 Chunk(Zone zone, GameplaySettings settings, ChunkId chunk, float lead)
|
||||
{
|
||||
var pose = zone.ChunkPose(chunk.Field, chunk.Index, Time(zone, lead));
|
||||
return float3(pose.x, ChunkHeight(zone, settings, pose, lead), pose.y);
|
||||
}
|
||||
|
||||
// A ship in a wormhole animation has its pose scripted by the step, not integrated from Velocity and TurnRate,
|
||||
// so it is drawn where the step put it: extrapolating a scripted pose draws a streak that resets every step.
|
||||
// A child is drawn where its parent is drawn, as the step copies the parent's pose onto it.
|
||||
|
|
|
|||
|
|
@ -533,7 +533,6 @@ public class ZoneRenderer : MonoBehaviour
|
|||
// SlimeRenderer.SpawnPositions[i] = _suns[i].Body.transform.position.Flatland();
|
||||
// }
|
||||
|
||||
Shader.SetGlobalFloat("_AsteroidVerticalOffset", ActionGameManager.Instance.Settings.PlanetSettings.AsteroidVerticalOffset);
|
||||
|
||||
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(MainCamera);
|
||||
bool isVisible(Bounds bounds) => GeometryUtility.TestPlanesAABB(planes, bounds);
|
||||
|
|
@ -559,7 +558,7 @@ public class ZoneRenderer : MonoBehaviour
|
|||
{
|
||||
var tx = t + i * count;
|
||||
var transform = transforms[tx];
|
||||
matrices[i][t] = Matrix4x4.TRS(new Vector3(transform.x,0,transform.y),
|
||||
matrices[i][t] = Matrix4x4.TRS(new Vector3(transform.x,DrawAhead.ChunkHeight(Zone,ItemManager.GameplaySettings,transform,lead),transform.y),
|
||||
Quaternion.Euler(
|
||||
cos(transform.z + (float)i / meshes.Length) * 100,
|
||||
sin(transform.z + (float)i / meshes.Length) * 100,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public sealed class DrawnPoseTests : IDisposable
|
|||
private const float StationDistance = 3f, StationPhase = .4f;
|
||||
private const float ShipLayerHeight = 2.5f;
|
||||
private const float OrbitalLayerHeight = 7.5f;
|
||||
private const float FloaterLayerHeight = -1.25f;
|
||||
// The sun's rail is parentless and off-centre, the shape ZoneGenerator gives a cluster root (FixedPosition = cluster centre).
|
||||
private static readonly float2 SunCentre = new float2(700f, -300f);
|
||||
|
||||
|
|
@ -88,7 +89,7 @@ public sealed class DrawnPoseTests : IDisposable
|
|||
DefaultEntitySettings = new EntitySettings(),
|
||||
Tiers = new[] { new RarityTier { Name = "Common", Quality = .5f, Rarity = 0, Color = new float3(1, 1, 1) } },
|
||||
QualityPriceModifier = new ExponentialLerp(),
|
||||
ShipLayerHeight = ShipLayerHeight, OrbitalLayerHeight = OrbitalLayerHeight
|
||||
ShipLayerHeight = ShipLayerHeight, OrbitalLayerHeight = OrbitalLayerHeight, FloaterLayerHeight = FloaterLayerHeight
|
||||
}, _ => { });
|
||||
|
||||
CultRecordKey Orbit(CultRecordKey parent, float distance, float phase, float2 fixedPosition = default)
|
||||
|
|
@ -347,6 +348,32 @@ public sealed class DrawnPoseTests : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
// The reticle (DrawAhead.Chunk) and the renderer's per-rock instance (DrawAhead.ChunkHeight on EvaluateBelt's drawn pose)
|
||||
// are one height: the field at the rock's planar position at the drawn time, plus the floater layer. Ruling asteroids-on-floater-layer.
|
||||
[Fact]
|
||||
public void AChunkIsDrawnOnTheFloaterLayerOverTheField()
|
||||
{
|
||||
var w = Build();
|
||||
Step(w, 1f / 60f, 301);
|
||||
const float lead = .01f;
|
||||
var time = w.Zone.ExactTime + lead;
|
||||
var drawn = new float4[w.Asteroids.Length];
|
||||
w.Zone.EvaluateBelt(w.Belt, drawn, time);
|
||||
var settings = w.Items.GameplaySettings;
|
||||
|
||||
var deep = 0;
|
||||
for (var i = 0; i < w.Asteroids.Length; i++)
|
||||
{
|
||||
var reticle = DrawAhead.Chunk(w.Zone, settings, new ChunkId(w.Belt, i), lead);
|
||||
var field = FieldAt(w, drawn[i].xy, time);
|
||||
AssertNear(drawn[i].xy, reticle.xz, 1e-3f, $"chunk {i} reticle xz");
|
||||
Assert.Equal(field + FloaterLayerHeight, reticle.y, 3);
|
||||
Assert.Equal(reticle.y, DrawAhead.ChunkHeight(w.Zone, settings, drawn[i], lead), 4);
|
||||
if (abs(field) > 1f) deep++;
|
||||
}
|
||||
Assert.True(deep > 0, "some rock sits where the field is more than a unit from zero, so a dropped field fails");
|
||||
}
|
||||
|
||||
// The term the shader takes sits on its node's rail at the drawn time: the lowering copies DrawAhead.Orbit of the term's
|
||||
// node and decides nothing, so a drawn term and the drawn planet share one pose at a non-zero lead.
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in a new issue