Aim at infinity along the view's pitch; delete the terrain intersection
The horizon fault was the level XZ projection, not the distance (operator, 2026-10-29). The untargeted look point is 10000 along the aim again, so the camera no longer jumps where the view ray crosses a terrain discontinuity; group aim points and crosshairs lift each planar firing bearing by the aim's pitch. Reverts the surface march ofaba02182band the field-height crosshair ofa9bbea509. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ffdba39ac2
commit
7a3c0c8fb8
2 changed files with 13 additions and 44 deletions
|
|
@ -1470,17 +1470,19 @@ public class ActionGameManager : MonoBehaviour
|
|||
else if (target.Entity != null)
|
||||
TargetIndicator.Target = DrawAhead.Position(target.Entity, lead).ToUnity();
|
||||
var distance = length(ViewDot.Target.ToCultMath() - ownDrawn);
|
||||
var ownField = DrawAhead.Height(CurrentEntity.Zone, ownDrawn.xz, lead);
|
||||
// The aim's pitch, applied to each barrel's planar bearing: the crosshair sits where the guns point at the view's
|
||||
// elevation, not on the ship's level plane (which is the horizon).
|
||||
var aim = CurrentEntity.Aim;
|
||||
var aimLevel = length(aim.xz);
|
||||
foreach (var (_, barrels, crosshair) in _articulationGroups)
|
||||
{
|
||||
var averagePosition = Vector3.zero;
|
||||
foreach (var barrel in barrels)
|
||||
averagePosition += barrel.position + barrel.forward * distance;
|
||||
{
|
||||
var bearing = new Vector2(barrel.forward.x, barrel.forward.z).normalized;
|
||||
averagePosition += barrel.position + new Vector3(bearing.x * aimLevel, aim.y, bearing.y * aimLevel) * distance;
|
||||
}
|
||||
averagePosition /= barrels.Length;
|
||||
// Shots fly over the field, so the crosshair rides it too: the aim point's own field height, plus the barrels' height
|
||||
// above the field under the ship. A level projection floats over downhill aim and sinks into uphill aim.
|
||||
var aimPlanar = float2(averagePosition.x, averagePosition.z);
|
||||
averagePosition.y += DrawAhead.Height(CurrentEntity.Zone, aimPlanar, lead) - ownField;
|
||||
crosshair.Target = averagePosition;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -405,10 +405,12 @@ public class EntityInstance : MonoBehaviour
|
|||
// The drawn pose first: the camera's LookAt and the barrels read this frame's pose, not the last frame's.
|
||||
var drawn = DrawAhead.Position(Entity, ActionGameManager.Clock.Lead);
|
||||
LocalSpace.localPosition = transform.position = drawn.ToUnity();
|
||||
var lead = ActionGameManager.Clock.Lead;
|
||||
var aimDistance = !Entity.Target.Value.IsNone
|
||||
? max(Entity.TargetRange, Entity.ItemManager.GameplaySettings.ConvergenceMinimumDistance)
|
||||
: SurfaceDistance(drawn, Entity.Aim, lead);
|
||||
: 10000;
|
||||
// The aim's pitch: a planar firing bearing is drawn at the same elevation as the view, so a group aims where the
|
||||
// player looks, not at the horizon of the ship's plane.
|
||||
var aimLevel = length(Entity.Aim.xz);
|
||||
LookAtPoint.position = transform.position + Entity.Aim.ToUnity() * aimDistance;
|
||||
foreach (var group in _groupAims)
|
||||
{
|
||||
|
|
@ -416,47 +418,12 @@ public class EntityInstance : MonoBehaviour
|
|||
if (weapon == null) { group.Value.position = LookAtPoint.position; continue; }
|
||||
var barrel = Barrels.TryGetValue(weapon.Item.Hardpoint, out var barrels) ? barrels[0].position : transform.position;
|
||||
var direction = FireControl.Solution(weapon, Entity, Entity.Target.Value).Direction;
|
||||
var aimAt = barrel + new Vector3(direction.x, 0, direction.y) * aimDistance;
|
||||
// Shots fly over the field: the group's aim point rides it, at the barrel's height above the field under the ship.
|
||||
aimAt.y += Entity.RideHeight(float2(aimAt.x, aimAt.z), DrawAhead.Time(Entity.Zone, lead)) - drawn.y;
|
||||
group.Value.position = aimAt;
|
||||
group.Value.position = barrel + new Vector3(direction.x * aimLevel, Entity.Aim.y, direction.y * aimLevel) * aimDistance;
|
||||
}
|
||||
if (_influenceInstance)
|
||||
_influenceInstance.position = new Vector3(drawn.x, 0, drawn.z);
|
||||
}
|
||||
|
||||
// How far along `aim` from `from` the view ray meets the surface the ship rides, so an untargeted aim lands where the
|
||||
// player looks on the field. Marches out in growing steps, then bisects the crossing; a ray that never comes down
|
||||
// (looking level or up) aims at the horizon.
|
||||
private float SurfaceDistance(CultMath.float3 from, CultMath.float3 aim, float lead)
|
||||
{
|
||||
const float horizon = 10000;
|
||||
var time = DrawAhead.Time(Entity.Zone, lead);
|
||||
float Above(float t)
|
||||
{
|
||||
var p = from + aim * t;
|
||||
return p.y - Entity.RideHeight(p.xz, time);
|
||||
}
|
||||
var near = Entity.ItemManager.GameplaySettings.ConvergenceMinimumDistance;
|
||||
if (Above(near) <= 0) return near;
|
||||
var step = max(near, 8f);
|
||||
for (var t = near; t < horizon; step *= 1.25f)
|
||||
{
|
||||
var next = min(t + step, horizon);
|
||||
if (Above(next) <= 0)
|
||||
{
|
||||
for (var i = 0; i < 12; i++)
|
||||
{
|
||||
var mid = (t + next) / 2;
|
||||
if (Above(mid) <= 0) next = mid; else t = mid;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
t = next;
|
||||
}
|
||||
return horizon;
|
||||
}
|
||||
|
||||
public virtual void OnDestroy()
|
||||
{
|
||||
if(_sensor!=null)
|
||||
|
|
|
|||
Loading…
Reference in a new issue