Radar-Sichtbarkeitsgates, Hider-Pings im Seek + Ping-Countdown
Radar: nur sichtbar bei >=1 Target, in First-Person und in der Seek-Phase (Overlay-Kamera getoggelt, Blip-Skripte laufen weiter). Singleton fuer Server-Zugriff. GameModeManager: Kamera + Tab-Moduswechsel erst ab gebundenem Lobby-Player (Inert-Zustand ohne Player, Orbit-Input geparkt). MatchManager: Server tickt im Seek alle radarPingInterval (30s) und broadcastet noch nicht gefundene Hider (NetworkObjectId + radarPingLifetime 3s) nur an Hunter-Clients; jeder Hunter loest lokal auf und spawnt Blips. Ping-Loop in die Seek-Coroutine gefaltet (EndMatch stoppt ihn mit). MatchHud: Ping-Countdown lokal aus Seek-Start + Kadenz berechnet, Format m:ss (0:30..0:01), ausserhalb Seek / bei deaktivierten Pings 0:00. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
23b51d07a4
commit
de82ce25de
4 files changed
+240
-12
No files matched your search
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
@@ -5,24 +6,53 @@ using UnityEngine;
|
||||
/// Spawns "Target" blips - clones of the child "Target Template" - each of which continuously points from
|
||||
/// the reference camera toward a world-space transform (visualising the bearing camera -> target) and then
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
public sealed class Radar : MonoBehaviour
|
||||
{
|
||||
/// <summary>The scene's single radar overlay (lives in the persistent Main scene). Hunter clients spawn
|
||||
/// hider blips onto it from MatchManager's radar-ping sweep.</summary>
|
||||
public static Radar Instance { get; private set; }
|
||||
|
||||
[Tooltip("Template each spawned Target is cloned from. Auto-resolves to the child \"Target Template\".")]
|
||||
[SerializeField] private Transform targetTemplate;
|
||||
|
||||
[Tooltip("Camera the direction is measured FROM (camera -> target). Auto-resolves to the Camera this radar sits under.")]
|
||||
[SerializeField] private Camera referenceCamera;
|
||||
|
||||
[Tooltip("Overlay camera that renders the radar. Its rendering is toggled off unless the radar should show " +
|
||||
"(at least one live target AND first-person active). Auto-resolves to the Camera this radar sits under.")]
|
||||
[SerializeField] private Camera radarCamera;
|
||||
|
||||
[Tooltip("First-person rig. The radar is only shown while first-person is active. Empty = found automatically.")]
|
||||
[SerializeField] private FirstPersonController firstPerson;
|
||||
|
||||
// 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>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
if (!targetTemplate)
|
||||
{
|
||||
var t = transform.Find("Target Template");
|
||||
if (t) targetTemplate = t;
|
||||
}
|
||||
if (!referenceCamera) referenceCamera = GetComponentInParent<Camera>();
|
||||
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
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (Instance == this) Instance = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,6 +81,35 @@ public sealed class Radar : MonoBehaviour
|
||||
|
||||
var blip = clone.GetComponent<RadarTarget>();
|
||||
blip.Init(target, referenceCamera, lifetime);
|
||||
_blips.Add(blip);
|
||||
return blip;
|
||||
}
|
||||
|
||||
// LateUpdate so the count reflects any blip that self-destructed this frame, in step with RadarTarget's aim.
|
||||
private void LateUpdate()
|
||||
{
|
||||
// Drop self-destructed blips (Destroy leaves a fake-null entry behind).
|
||||
for (int i = _blips.Count - 1; i >= 0; i--)
|
||||
if (!_blips[i]) _blips.RemoveAt(i);
|
||||
|
||||
bool visible = _blips.Count > 0 && firstPerson && firstPerson.enabled && InSeekPhase();
|
||||
ApplyVisibility(visible);
|
||||
}
|
||||
|
||||
// The radar only makes sense during the seek phase (hunters chasing hiders). Blips only spawn then anyway,
|
||||
// but a blip's lifetime can outlast the phase edge, so gating here hides the overlay the instant Seek ends.
|
||||
private static bool InSeekPhase()
|
||||
{
|
||||
var m = MatchManager.Instance;
|
||||
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)
|
||||
{
|
||||
if (radarCamera && radarCamera.enabled != visible)
|
||||
radarCamera.enabled = visible;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user