using UnityEngine; /// /// Attached to the group leader's GameObject. /// Scales the leader's sphere to reflect group size and renders a floating /// count label above it using a World-Space Canvas + TextMesh. /// Follower agents are hidden (renderer disabled) while in the group. /// [RequireComponent(typeof(MeshRenderer))] public class AgentGroupVisual : MonoBehaviour { private AgentGroup group; private MeshRenderer meshRenderer; private GameObject labelObject; private TextMesh countLabel; // Base scale of a solo agent is 0.5 (set in CreateDefaultAgentPrefab) private const float BASE_SCALE = 0.5f; // Each additional member adds 10% to radius (so group of 9 is ~1.4× base) private const float SCALE_GROWTH = 0.1f; private static readonly Color SOLO_COLOR = Color.cyan; private static readonly Color GROUP_COLOR = new Color(1f, 0.55f, 0f); // orange public void Init(AgentGroup g) { group = g; meshRenderer = GetComponent(); CreateLabel(); Refresh(); } public void Refresh() { if (group == null) return; int size = group.Size; // Scale sphere float scale = BASE_SCALE + BASE_SCALE * SCALE_GROWTH * (size - 1); transform.localScale = Vector3.one * scale; // Color: solo = cyan, grouped = orange, larger group = brighter orange meshRenderer.material.color = size > 1 ? GROUP_COLOR : SOLO_COLOR; // Count label – only show for groups of 2+ if (labelObject != null) { labelObject.SetActive(size > 1); if (countLabel != null) countLabel.text = size.ToString(); } // Hide/show follower renderers foreach (var member in group.Members) { if (member == group.Leader) continue; var mr = member.GetComponent(); if (mr != null) mr.enabled = false; var lr = member.GetComponent(); if (lr != null) lr.enabled = false; } } private void CreateLabel() { labelObject = new GameObject("GroupCountLabel"); labelObject.transform.SetParent(transform, false); // Float above the sphere labelObject.transform.localPosition = new Vector3(0f, 0.8f, 0f); countLabel = labelObject.AddComponent(); countLabel.text = "1"; countLabel.fontSize = 48; countLabel.alignment = TextAlignment.Center; countLabel.anchor = TextAnchor.MiddleCenter; countLabel.color = Color.white; countLabel.characterSize = 0.05f; // Always face camera labelObject.AddComponent(); } void OnDestroy() { if (labelObject != null) Destroy(labelObject); // Restore solo scale/color if visual is removed (member left group) transform.localScale = Vector3.one * BASE_SCALE; if (meshRenderer != null) meshRenderer.material.color = SOLO_COLOR; } } /// Keeps the TextMesh facing the main camera. public class BillboardLabel : MonoBehaviour { void LateUpdate() { if (Camera.main == null) return; transform.forward = Camera.main.transform.forward; } }