248 lines
7.9 KiB
C#
248 lines
7.9 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
/// <summary>
|
|
/// TeamIndicator - Creates an overhead team marker above characters to differentiate teammates from enemies.
|
|
/// Attach to character prefabs or add dynamically via TeamIndicatorManager.
|
|
/// </summary>
|
|
public class TeamIndicator : MonoBehaviour
|
|
{
|
|
[Header("Indicator Settings")]
|
|
[SerializeField] private float heightOffset = 2.5f;
|
|
[SerializeField] private float indicatorSize = 0.3f;
|
|
|
|
[Header("Team Colors")]
|
|
[SerializeField] private Color allyColor = new Color(0.2f, 0.8f, 0.2f, 1f); // Green
|
|
[SerializeField] private Color enemyColor = new Color(0.9f, 0.2f, 0.2f, 1f); // Red
|
|
[SerializeField] private Color controlledColor = new Color(0.2f, 0.6f, 1f, 1f); // Blue for currently controlled
|
|
|
|
[Header("Visual Options")]
|
|
[SerializeField] private bool showOnAllies = true;
|
|
[SerializeField] private bool showOnEnemies = true;
|
|
[SerializeField] private bool hideWhenControlled = true;
|
|
[SerializeField] private float fadeDistance = 50f; // Fade out at this distance
|
|
|
|
private GameObject indicatorObject;
|
|
private SpriteRenderer spriteRenderer;
|
|
private Camera mainCamera;
|
|
private TeamMember teamMember;
|
|
private string myTeamTag;
|
|
private bool isCurrentlyControlled = false;
|
|
|
|
// Static reference to find the current player for team comparison
|
|
private static Transform currentPlayerTransform;
|
|
private static string currentPlayerTeamTag = "Player";
|
|
|
|
private void Start()
|
|
{
|
|
// Only activate in Cash System mode
|
|
if (SelectionOptions.Instance == null || !SelectionOptions.Instance.isCashSystemSelected)
|
|
{
|
|
enabled = false;
|
|
return;
|
|
}
|
|
|
|
mainCamera = Camera.main;
|
|
teamMember = GetComponent<TeamMember>();
|
|
myTeamTag = gameObject.tag;
|
|
|
|
CreateIndicator();
|
|
UpdateIndicatorColor();
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (indicatorObject == null || mainCamera == null) return;
|
|
|
|
// Update position to stay above character
|
|
indicatorObject.transform.position = transform.position + Vector3.up * heightOffset;
|
|
|
|
// Billboard effect - always face camera
|
|
indicatorObject.transform.rotation = Quaternion.LookRotation(
|
|
indicatorObject.transform.position - mainCamera.transform.position
|
|
);
|
|
|
|
// Check if this character is currently controlled
|
|
bool wasControlled = isCurrentlyControlled;
|
|
isCurrentlyControlled = teamMember != null && teamMember.IsPlayerControlled;
|
|
|
|
// Update static reference if we're the controlled character
|
|
if (isCurrentlyControlled)
|
|
{
|
|
currentPlayerTransform = transform;
|
|
currentPlayerTeamTag = myTeamTag;
|
|
}
|
|
|
|
// Update color if control status changed
|
|
if (wasControlled != isCurrentlyControlled)
|
|
{
|
|
UpdateIndicatorColor();
|
|
}
|
|
|
|
// Handle visibility based on settings
|
|
UpdateVisibility();
|
|
|
|
// Fade based on distance from camera
|
|
UpdateFade();
|
|
}
|
|
|
|
private void CreateIndicator()
|
|
{
|
|
// Create indicator game object
|
|
indicatorObject = new GameObject($"{gameObject.name}_TeamIndicator");
|
|
indicatorObject.transform.position = transform.position + Vector3.up * heightOffset;
|
|
|
|
// Add sprite renderer for the indicator
|
|
spriteRenderer = indicatorObject.AddComponent<SpriteRenderer>();
|
|
spriteRenderer.sprite = CreateCircleSprite();
|
|
spriteRenderer.sortingOrder = 100; // Ensure it renders on top
|
|
|
|
// Set initial size
|
|
indicatorObject.transform.localScale = Vector3.one * indicatorSize;
|
|
}
|
|
|
|
private Sprite CreateCircleSprite()
|
|
{
|
|
// Create a simple diamond/arrow shaped indicator texture
|
|
int size = 64;
|
|
Texture2D texture = new Texture2D(size, size);
|
|
Color transparent = new Color(0, 0, 0, 0);
|
|
|
|
// Fill with transparent
|
|
for (int x = 0; x < size; x++)
|
|
{
|
|
for (int y = 0; y < size; y++)
|
|
{
|
|
texture.SetPixel(x, y, transparent);
|
|
}
|
|
}
|
|
|
|
// Draw a downward pointing triangle/arrow
|
|
int centerX = size / 2;
|
|
int topY = size - 8;
|
|
int bottomY = 8;
|
|
|
|
for (int y = bottomY; y <= topY; y++)
|
|
{
|
|
float progress = (float)(y - bottomY) / (topY - bottomY);
|
|
int halfWidth = (int)(progress * (size / 2 - 4));
|
|
|
|
for (int x = centerX - halfWidth; x <= centerX + halfWidth; x++)
|
|
{
|
|
// Create a border effect
|
|
bool isBorder = Mathf.Abs(x - (centerX - halfWidth)) < 3 ||
|
|
Mathf.Abs(x - (centerX + halfWidth)) < 3 ||
|
|
y == bottomY || y >= topY - 2;
|
|
|
|
Color col = isBorder ? Color.white : Color.white;
|
|
col.a = isBorder ? 1f : 0.8f;
|
|
texture.SetPixel(x, y, col);
|
|
}
|
|
}
|
|
|
|
texture.Apply();
|
|
texture.filterMode = FilterMode.Bilinear;
|
|
|
|
return Sprite.Create(texture, new Rect(0, 0, size, size), new Vector2(0.5f, 0f), size);
|
|
}
|
|
|
|
private void UpdateIndicatorColor()
|
|
{
|
|
if (spriteRenderer == null) return;
|
|
|
|
// Currently controlled character
|
|
if (isCurrentlyControlled)
|
|
{
|
|
spriteRenderer.color = controlledColor;
|
|
return;
|
|
}
|
|
|
|
// Determine if ally or enemy relative to player
|
|
bool isAlly = (myTeamTag == currentPlayerTeamTag);
|
|
|
|
if (isAlly)
|
|
{
|
|
spriteRenderer.color = allyColor;
|
|
}
|
|
else
|
|
{
|
|
spriteRenderer.color = enemyColor;
|
|
}
|
|
}
|
|
|
|
private void UpdateVisibility()
|
|
{
|
|
if (spriteRenderer == null) return;
|
|
|
|
bool shouldShow = true;
|
|
|
|
// Hide if this is the controlled character and setting is enabled
|
|
if (hideWhenControlled && isCurrentlyControlled)
|
|
{
|
|
shouldShow = false;
|
|
}
|
|
|
|
// Check ally/enemy visibility settings
|
|
bool isAlly = (myTeamTag == currentPlayerTeamTag);
|
|
if (isAlly && !showOnAllies) shouldShow = false;
|
|
if (!isAlly && !showOnEnemies) shouldShow = false;
|
|
|
|
indicatorObject.SetActive(shouldShow);
|
|
}
|
|
|
|
private void UpdateFade()
|
|
{
|
|
if (spriteRenderer == null || mainCamera == null) return;
|
|
|
|
float distance = Vector3.Distance(mainCamera.transform.position, transform.position);
|
|
|
|
// Calculate alpha based on distance
|
|
float alpha = Mathf.Clamp01(1f - (distance / fadeDistance));
|
|
alpha = Mathf.Max(alpha, 0.3f); // Minimum alpha
|
|
|
|
Color currentColor = spriteRenderer.color;
|
|
currentColor.a = alpha;
|
|
spriteRenderer.color = currentColor;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (indicatorObject != null)
|
|
{
|
|
Destroy(indicatorObject);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Force update the indicator color (call after team changes)
|
|
/// </summary>
|
|
public void RefreshIndicator()
|
|
{
|
|
myTeamTag = gameObject.tag;
|
|
UpdateIndicatorColor();
|
|
UpdateVisibility();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set indicator visibility
|
|
/// </summary>
|
|
public void SetVisible(bool visible)
|
|
{
|
|
if (indicatorObject != null)
|
|
{
|
|
indicatorObject.SetActive(visible);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Static method to update all indicators when player changes
|
|
/// </summary>
|
|
public static void RefreshAllIndicators()
|
|
{
|
|
foreach (var indicator in FindObjectsOfType<TeamIndicator>())
|
|
{
|
|
indicator.RefreshIndicator();
|
|
}
|
|
}
|
|
}
|