Files
chameleon/Assets/Scripts/Components/RadarTarget.cs
T
adminandClaude Fable 5 6c03e5d3f6 Refactor Assets/Scripts: trim restating comments, minor structure cleanups
Sweep over 48 files (Editor/ excluded): remove comments that restate the
code, condense class summaries, fix three stale doc statements
(HsvColorPicker alpha bar, PaintHud layoutPrefab, MasterVolume
FallbackDefault). Inline two single-use wrappers (IsPointerOverUi,
BuildModes), drop an unused using, replace a magic literal with the
existing ParallaxBase constant, and convert ~10 UnityEngine.Object null
checks to the implicit-bool convention. No serialized fields, signatures,
RPC/NetworkVariable names, defaults, or #if blocks touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 08:29:18 +02:00

139 lines
6.3 KiB
C#

using UnityEngine;
/// <summary>
/// A single radar blip spawned by <see cref="Radar"/>. Each frame it orients its forward (+Z, where the
/// "Point" marker sits) along the bearing reference camera -> world target, and self-destructs once its
/// lifetime elapses - or earlier if the target is destroyed. The point encodes the two things the flat
/// disc can't show via position alone: <see cref="forwardGradient"/> tints it by how far the target sits
/// ahead of / behind the camera, and its scale shrinks with camera -> target distance.
///
/// On top of the radar-wide fade, each blip ramps its own <see cref="_fade"/> in on spawn and out at end
/// of life (or when its world target vanishes), so blips never pop. The factor persists across
/// <see cref="Refresh"/> so a refreshed blip is pulled back to full opacity rather than flickering to
/// zero first.
/// </summary>
[DisallowMultipleComponent]
public sealed class RadarTarget : MonoBehaviour
{
public Renderer pointRenderer;
[Tooltip("Point tint by bearing: sampled at 0 when the target is dead ahead of the camera, at 1 when directly behind. Flip the keys for the reverse.")]
[SerializeField] Gradient forwardGradient;
[Tooltip("Point transform scale at the near (x) and far (y) end of pointDistanceRange.")]
[SerializeField] Vector2 pointDistanceScale;
[Tooltip("camera -> target distance mapped onto pointDistanceScale: x = near distance, y = far distance.")]
[SerializeField] Vector2 pointDistanceRange;
[Header("Fade")]
[Tooltip("Per-blip fade-in speed in alpha units per second when the blip appears. e.g. 6 = ~0.17s. 0 = appear instantly.")]
[SerializeField] float fadeInSpeed = 6f;
[Tooltip("Per-blip fade-out speed in alpha units per second at the end of life / when the target vanishes. e.g. 4 = ~0.25s. 0 = vanish instantly.")]
[SerializeField] float fadeOutSpeed = 4f;
private Transform _target;
private Camera _camera;
private float _lifetime;
private float _age;
private bool _initialised;
private float _fade; // per-blip 0..1 ramp, multiplied on top of the radar-wide fade; persists across Refresh
private MaterialPropertyBlock _mpb;
private Color _pointColor = Color.white; // last gradient-evaluated point colour; its alpha is scaled by the radar fade
private static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");
public Transform Target => _target;
public float RemainingLifetime => Mathf.Max(0f, _lifetime - _age);
public void Init(Transform target, Camera referenceCamera, float lifetime)
{
_target = target;
_camera = referenceCamera;
_lifetime = lifetime;
_age = 0f;
_initialised = true;
Aim();
PushPointColor();
}
/// <summary>Restarts this blip's countdown to <paramref name="lifetime"/> seconds. Used when a ping arrives
/// for a target this radar already tracks: the existing blip is refreshed instead of stacking a duplicate.</summary>
public void Refresh(float lifetime)
{
_lifetime = lifetime;
_age = 0f;
}
// LateUpdate so the aim uses the camera's final position/rotation for this frame.
private void LateUpdate()
{
if (!_initialised) return;
_age += Time.deltaTime;
// Fade out at the very end of life, or immediately if the world target vanished (e.g. a caught hider)
// instead of dangling. The fade-out window equals the time to ramp 1 -> 0 at fadeOutSpeed, so the point
// reaches full transparency right as the lifetime elapses; then the blip destroys itself.
float fadeOutWindow = fadeOutSpeed > 0f ? 1f / fadeOutSpeed : 0f;
bool fadingOut = !_target || RemainingLifetime <= fadeOutWindow;
float goal = fadingOut ? 0f : 1f;
float speed = Mathf.Max(0f, fadingOut ? fadeOutSpeed : fadeInSpeed);
_fade = Mathf.MoveTowards(_fade, goal, speed * Time.deltaTime);
if (fadingOut && (speed <= 0f || _fade <= 0.0001f))
{
Destroy(gameObject);
return;
}
Aim(); // keeps last orientation/colour if the target is gone (Aim early-returns)
PushPointColor(); // every frame so the alpha tracks both the radar fade and this blip's own fade
}
private void Aim()
{
if (!_target || !_camera) return;
Vector3 dir = _target.position - _camera.transform.position;
float sqr = dir.sqrMagnitude;
if (sqr < 1e-8f) return; // camera sitting on the target -> keep the last orientation/colour/scale
transform.rotation = Quaternion.LookRotation(dir);
float distance = Mathf.Sqrt(sqr);
ApplyDistanceScale(distance);
ApplyForwardColor(dir / distance);
}
// Shrinks the blip with distance: pointDistanceRange (near, far) remapped onto pointDistanceScale (near, far), clamped.
private void ApplyDistanceScale(float distance)
{
if (!pointRenderer) return;
float t = Mathf.InverseLerp(pointDistanceRange.x, pointDistanceRange.y, distance);
float s = Mathf.Lerp(pointDistanceScale.x, pointDistanceScale.y, t);
pointRenderer.transform.localScale = new Vector3(s, s, s);
}
// Tints the point's base colour by how far the target sits ahead of (0) vs directly behind (1) the camera.
// Only caches the colour here; PushPointColor writes it (with the fade applied) so the alpha can track the
// radar fade every frame independent of when the bearing last changed.
private void ApplyForwardColor(Vector3 dirNormalized)
{
if (forwardGradient == null) return;
float t = Vector3.Angle(_camera.transform.forward, dirNormalized) / 180f;
_pointColor = forwardGradient.Evaluate(t);
}
// Writes the point's _BaseColor with its alpha scaled by both the radar's shared fade factor (so blips fade in
// step with the disc) and this blip's own fade (so it eases in on spawn and out at the end of its life).
private void PushPointColor()
{
if (!pointRenderer) return;
Color c = _pointColor;
c.a *= (Radar.Instance ? Radar.Instance.CurrentFade : 1f) * _fade;
_mpb ??= new MaterialPropertyBlock();
pointRenderer.GetPropertyBlock(_mpb);
_mpb.SetColor(BaseColorId, c);
pointRenderer.SetPropertyBlock(_mpb);
}
}