Radar: fade in/out statt hartem Enable-Toggle

Gemeinsamer 0..1-Fade-Faktor treibt Disc-Alpha (baseAlpha * fade via MPB),
Blip-Alpha (RadarTarget, im Gleichschritt) und Radar-Scale (0.8 -> 1.0).
Fade-in/-out-Speed separat einstellbar; Kamera bleibt an solange fade > 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 4.8 committed 2026-07-06 12:23:42 +02:00
1 parent 65bd6f8efc
commit cad5015d42
2 files changed
+96 -12

No files matched your search

+79 -10
View File
@@ -8,8 +8,10 @@ using UnityEngine;
/// destroys itself after a given lifetime. See <see cref="RadarTarget"/> for the per-blip behaviour.
///
/// The whole radar overlay is only shown while it is useful: at least one live target, first-person is active,
/// AND the match is in its Seek phase. It is hidden by switching the overlay camera's rendering off (not by
/// deactivating the GameObjects), so hidden blips keep counting down their lifetime and self-destruct on schedule.
/// AND the match is in its Seek phase. Instead of snapping on/off it fades: a shared 0..1 factor (<see cref="CurrentFade"/>)
/// drives the alpha of every (transparent) radar renderer - the disc here, the blip points in <see cref="RadarTarget"/> -
/// and scales the disc from <see cref="hiddenScale"/> up to 1. Fade-in and fade-out speeds are independent. The overlay
/// camera is switched off only once fully faded out, so hidden blips keep counting down their lifetime meanwhile.
/// </summary>
[DisallowMultipleComponent]
public sealed class Radar : MonoBehaviour
@@ -31,9 +33,28 @@ public sealed class Radar : MonoBehaviour
[Tooltip("First-person rig. The radar is only shown while first-person is active. Empty = found automatically.")]
[SerializeField] private FirstPersonController firstPerson;
[Header("Fade")]
[Tooltip("Fade-in speed in alpha units per second (0 -> 1). e.g. 5 = ~0.2s to fully appear.")]
[SerializeField] private float fadeInSpeed = 5f;
[Tooltip("Fade-out speed in alpha units per second (1 -> 0). e.g. 3 = ~0.33s to fully vanish.")]
[SerializeField] private float fadeOutSpeed = 3f;
[Tooltip("Disc scale multiplier while fully hidden (fade 0); grows to 1 as it fades in, and back down on fade-out.")]
[SerializeField] private float hiddenScale = 0.8f;
// Live blips, pruned as they self-destruct; the radar shows only while at least one is alive.
private readonly List<RadarTarget> _blips = new List<RadarTarget>();
// Shared 0..1 visibility factor: drives disc/blip alpha and disc scale. Ramped in LateUpdate.
private float _fade;
/// <summary>Current 0..1 fade factor. Blips multiply their point alpha by this so they fade in step with the disc.</summary>
public float CurrentFade => _fade;
private Vector3 _baseScale; // authored disc scale, captured once; fade lerps hiddenScale..1 on top
private Renderer[] _staticRenderers; // radar's own renderers (the disc); the template subtree is excluded
private Color[] _staticBaseColors; // their full-opacity _BaseColor; alpha is scaled by _fade each frame
private MaterialPropertyBlock _mpb;
private static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");
private void Awake()
{
Instance = this;
@@ -47,7 +68,30 @@ public sealed class Radar : MonoBehaviour
if (!radarCamera) radarCamera = GetComponentInParent<Camera>();
if (!firstPerson) firstPerson = FindFirstObjectByType<FirstPersonController>(FindObjectsInactive.Include);
ApplyVisibility(false); // hidden until a target exists, first-person is live AND the match is seeking
_baseScale = transform.localScale;
CacheStaticRenderers();
_fade = 0f; // hidden until a target exists, first-person is live AND the match is seeking
ApplyFade();
}
// Gathers the radar's own renderers (the disc) once, with their full-opacity _BaseColor, so their alpha can be
// scaled by _fade each frame. The "Target Template" subtree is skipped: it is the blip prototype, and its clones
// fade themselves via RadarTarget (which owns their per-blip colour).
private void CacheStaticRenderers()
{
var all = GetComponentsInChildren<Renderer>(true);
var renderers = new List<Renderer>(all.Length);
var colors = new List<Color>(all.Length);
foreach (var r in all)
{
if (targetTemplate && r.transform.IsChildOf(targetTemplate)) continue;
renderers.Add(r);
var mat = r.sharedMaterial;
colors.Add(mat && mat.HasProperty(BaseColorId) ? mat.GetColor(BaseColorId) : Color.white);
}
_staticRenderers = renderers.ToArray();
_staticBaseColors = colors.ToArray();
}
private void OnDestroy()
@@ -93,7 +137,14 @@ public sealed class Radar : MonoBehaviour
if (!_blips[i]) _blips.RemoveAt(i);
bool visible = _blips.Count > 0 && firstPerson && firstPerson.enabled && InSeekPhase();
ApplyVisibility(visible);
// Ramp the shared factor toward shown/hidden with the matching speed, so the whole overlay fades
// (alpha + scale) instead of snapping. A mid-fade visibility flip reverses smoothly.
float target = visible ? 1f : 0f;
float speed = Mathf.Max(0f, visible ? fadeInSpeed : fadeOutSpeed);
_fade = Mathf.MoveTowards(_fade, target, speed * Time.deltaTime);
ApplyFade();
}
// The radar only makes sense during the seek phase (hunters chasing hiders). Blips only spawn then anyway,
@@ -104,12 +155,30 @@ public sealed class Radar : MonoBehaviour
return m && m.MatchActive && m.LocalSubPhase == MatchManager.MatchSubPhase.Seek;
}
// Shows/hides the whole radar overlay in one toggle (disc + blips) by switching the overlay camera's
// rendering. The GameObjects stay active, so blips keep ticking down their lifetime while hidden. The
// overlay renders only the Radar layer, so nothing else is affected.
private void ApplyVisibility(bool visible)
// Applies the current _fade to the whole overlay: disc scale (hiddenScale..1), disc alpha (baseAlpha*fade),
// and the overlay camera - switched off only once fully faded out, so blips keep ticking their lifetime while
// hidden and no rendering happens for an invisible radar. Blips fade themselves via RadarTarget/CurrentFade.
private void ApplyFade()
{
if (radarCamera && radarCamera.enabled != visible)
radarCamera.enabled = visible;
transform.localScale = _baseScale * Mathf.Lerp(hiddenScale, 1f, _fade);
if (_staticRenderers != null)
{
_mpb ??= new MaterialPropertyBlock();
for (int i = 0; i < _staticRenderers.Length; i++)
{
var r = _staticRenderers[i];
if (!r) continue;
Color c = _staticBaseColors[i];
c.a *= _fade;
r.GetPropertyBlock(_mpb);
_mpb.SetColor(BaseColorId, c);
r.SetPropertyBlock(_mpb);
}
}
bool render = _fade > 0.0001f;
if (radarCamera && radarCamera.enabled != render)
radarCamera.enabled = render;
}
}
+17 -2
View File
@@ -27,6 +27,7 @@ public sealed class RadarTarget : MonoBehaviour
private bool _initialised;
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;
@@ -40,6 +41,7 @@ public sealed class RadarTarget : MonoBehaviour
_age = 0f;
_initialised = true;
Aim();
PushPointColor();
}
// LateUpdate so the aim uses the camera's final position/rotation for this frame.
@@ -62,6 +64,7 @@ public sealed class RadarTarget : MonoBehaviour
}
Aim();
PushPointColor(); // every frame so the blip's alpha tracks the radar fade even when Aim early-returns
}
private void Aim()
@@ -88,13 +91,25 @@ public sealed class RadarTarget : MonoBehaviour
}
// 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 (!pointRenderer || forwardGradient == null) return;
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 the radar's shared fade factor, so blips fade in/out
// in step with the disc instead of the overlay snapping on/off.
private void PushPointColor()
{
if (!pointRenderer) return;
Color c = _pointColor;
c.a *= Radar.Instance ? Radar.Instance.CurrentFade : 1f;
_mpb ??= new MaterialPropertyBlock();
pointRenderer.GetPropertyBlock(_mpb);
_mpb.SetColor(BaseColorId, forwardGradient.Evaluate(t));
_mpb.SetColor(BaseColorId, c);
pointRenderer.SetPropertyBlock(_mpb);
}
}