| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- using UnityEngine;
- /// <summary>
- /// 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.
- /// </summary>
- [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<MeshRenderer>();
- 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<MeshRenderer>();
- if (mr != null) mr.enabled = false;
- var lr = member.GetComponent<LineRenderer>();
- 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<TextMesh>();
- 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<BillboardLabel>();
- }
- 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;
- }
- }
- /// <summary>Keeps the TextMesh facing the main camera.</summary>
- public class BillboardLabel : MonoBehaviour
- {
- void LateUpdate()
- {
- if (Camera.main == null) return;
- transform.forward = Camera.main.transform.forward;
- }
- }
|