sea-battle/Assets/Scripts/UI/EnemyCardController.cs

298 lines
8.6 KiB
C#

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class EnemyCardController : MonoBehaviour
{
[Header("UI Elements")]
public Image avatarImage;
public Animator avatarAnimator;
public TMP_Text nicknameText;
public TMP_Text dialogueText;
public RectTransform dialoguePanel;
[Header("Settings")]
public float typingSpeed = 0.05f;
public float panelExpandWidth = 300f;
public float panelExpandSpeed = 5f;
[Header("Animation names")]
public string idleAnimationName = "Idle_bot_1";
public string transitionIn = "forvard_bot";
public string transitionOut = "back_bot";
private Coroutine panelAnimCoroutine;
private Coroutine textTypingCoroutine;
private Vector2 dialogueOriginalPos;
private WaitForSeconds cachedTypingWait;
private System.Collections.Generic.HashSet<string> availableStates = new System.Collections.Generic.HashSet<string>();
private void Awake()
{
if (dialoguePanel != null)
dialogueOriginalPos = dialoguePanel.anchoredPosition;
cachedTypingWait = new WaitForSeconds(typingSpeed);
ValidateReferences();
}
private void OnValidate()
{
ValidateReferences();
}
private void ValidateReferences()
{
if (avatarImage == null) Debug.LogWarning($"[{name}] avatarImage íå íàçíà÷åí!", this);
if (nicknameText == null) Debug.LogWarning($"[{name}] nicknameText íå íàçíà÷åí!", this);
if (dialogueText == null) Debug.LogWarning($"[{name}] dialogueText íå íàçíà÷åí!", this);
if (dialoguePanel == null) Debug.LogWarning($"[{name}] dialoguePanel íå íàçíà÷åí!", this);
}
private void OnDisable()
{
StopAllAnimations();
ResetUIState();
}
public void SetEnemy(EnemyData enemy)
{
if (enemy == null)
{
Debug.LogWarning($"[{name}] SetEnemy: enemy is null!");
return;
}
if (nicknameText != null)
nicknameText.text = enemy.nickname;
SetupAnimatorOrSprite(enemy);
ResetUIState();
// Óñòàíàâëèâàåì ïîðÿäîê ïàíåëè (òîëüêî êîãäà îáúåêò àêòèâåí)
if (dialoguePanel != null && gameObject.activeInHierarchy)
dialoguePanel.SetSiblingIndex(0);
}
private void SetupAnimatorOrSprite(EnemyData enemy)
{
availableStates.Clear();
if (enemy.animatorOverride != null && avatarAnimator != null)
{
avatarAnimator.runtimeAnimatorController = enemy.animatorOverride;
avatarAnimator.enabled = true;
// Êýøèðóåì äîñòóïíûå êëèïû îäèí ðàç
var overrides = new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<AnimationClip, AnimationClip>>();
enemy.animatorOverride.GetOverrides(overrides);
foreach (var pair in overrides)
{
if (pair.Value != null) // Åñòü ïåðåîïðåäåë¸ííûé êëèï
availableStates.Add(pair.Key.name);
}
SetEmotion(idleAnimationName);
}
else
{
if (avatarAnimator != null)
avatarAnimator.enabled = false;
if (enemy.characterSprite != null && avatarImage != null)
avatarImage.sprite = enemy.characterSprite;
}
}
private void ResetUIState()
{
if (dialogueText != null)
dialogueText.text = "";
if (dialoguePanel != null)
{
dialoguePanel.anchoredPosition = dialogueOriginalPos;
}
}
private void StopAllAnimations()
{
if (panelAnimCoroutine != null)
{
StopCoroutine(panelAnimCoroutine);
panelAnimCoroutine = null;
}
if (textTypingCoroutine != null)
{
StopCoroutine(textTypingCoroutine);
textTypingCoroutine = null;
}
}
/// <summary>
/// Îòêðûâàåò êàðòî÷êó ñ àíèìàöèåé, âûçûâàåò callback êîãäà îòêðûëàñü
/// </summary>
public void ShowCard(string emotionState, System.Action onShown = null)
{
if (panelAnimCoroutine != null)
StopCoroutine(panelAnimCoroutine);
panelAnimCoroutine = StartCoroutine(ShowCardCoroutine(emotionState, onShown));
}
/// <summary>
/// Çàêðûâàåò êàðòî÷êó ñ àíèìàöèåé, âûçûâàåò callback êîãäà çàêðûëàñü
/// </summary>
public void HideCard(System.Action onHidden = null)
{
if (panelAnimCoroutine != null)
StopCoroutine(panelAnimCoroutine);
panelAnimCoroutine = StartCoroutine(HideCardCoroutine(onHidden));
}
/// <summary>
/// Ïå÷àòàåò òåêñò ïîñèìâîëüíî, âûçûâàåò callback ïî îêîí÷àíèè
/// </summary>
public void TypeText(string text, System.Action onComplete = null, bool skipSizePreparation = false)
{
if (textTypingCoroutine != null)
StopCoroutine(textTypingCoroutine);
textTypingCoroutine = StartCoroutine(TypeTextCoroutine(text, onComplete, skipSizePreparation));
}
/// <summary>
/// Ìãíîâåííî óñòàíàâëèâàåò òåêñò áåç àíèìàöèè ïå÷àòè
/// </summary>
public void SetTextImmediate(string text)
{
if (textTypingCoroutine != null)
{
StopCoroutine(textTypingCoroutine);
textTypingCoroutine = null;
}
if (dialogueText != null)
dialogueText.text = text;
}
/// <summary>
/// Ïîäãîòàâëèâàåò ðàçìåð òåêñòà çàðàíåå (÷òîáû èçáåæàòü "áëèêà" ïðè îòêðûòèè ïàíåëè)
/// </summary>
public IEnumerator PrepareTextSizeAsync(string text)
{
yield return PrepareTextSize(text);
}
private IEnumerator ShowCardCoroutine(string emotionState, System.Action onShown)
{
if (dialoguePanel == null) yield break;
SetEmotion(transitionIn);
Vector2 hiddenPos = dialogueOriginalPos;
Vector2 shownPos = hiddenPos + new Vector2(panelExpandWidth, 0);
float t = 0f;
while (t < 1f)
{
t += Time.deltaTime * panelExpandSpeed;
dialoguePanel.anchoredPosition = Vector2.Lerp(hiddenPos, shownPos, t);
yield return null;
}
dialoguePanel.anchoredPosition = shownPos;
SetEmotion(emotionState);
onShown?.Invoke();
}
private IEnumerator HideCardCoroutine(System.Action onHidden)
{
if (dialoguePanel == null) yield break;
SetEmotion(transitionOut);
if (dialogueText != null)
dialogueText.text = "";
Vector2 hiddenPos = dialogueOriginalPos;
Vector2 shownPos = hiddenPos + new Vector2(panelExpandWidth, 0);
float t = 0f;
while (t < 1f)
{
t += Time.deltaTime * panelExpandSpeed;
dialoguePanel.anchoredPosition = Vector2.Lerp(shownPos, hiddenPos, t);
yield return null;
}
dialoguePanel.anchoredPosition = hiddenPos;
SetEmotion(idleAnimationName);
onHidden?.Invoke();
}
private IEnumerator TypeTextCoroutine(string text, System.Action onComplete, bool skipSizePreparation)
{
if (dialogueText == null) yield break;
// Ïîäãîòîâêà ðàçìåðà øðèôòà (ïðîïóñêàåì åñëè óæå ñäåëàíî)
if (!skipSizePreparation)
{
yield return PrepareTextSize(text);
}
// Ïå÷àòü ïî ñèìâîëàì ÷åðåç maxVisibleCharacters (îïòèìèçàöèÿ)
dialogueText.text = text;
dialogueText.ForceMeshUpdate();
int totalChars = dialogueText.textInfo.characterCount;
dialogueText.maxVisibleCharacters = 0;
for (int i = 0; i <= totalChars; i++)
{
dialogueText.maxVisibleCharacters = i;
yield return cachedTypingWait;
}
onComplete?.Invoke();
}
private IEnumerator PrepareTextSize(string text)
{
if (dialogueText == null) yield break;
dialogueText.enableWordWrapping = true;
dialogueText.overflowMode = TextOverflowModes.Overflow;
dialogueText.text = text;
dialogueText.enableAutoSizing = true;
dialogueText.fontSizeMin = 5;
yield return null; // Æä¸ì êàäð äëÿ ðàñ÷¸òà
float finalFontSize = dialogueText.fontSize;
dialogueText.enableAutoSizing = false;
dialogueText.fontSize = finalFontSize;
dialogueText.text = "";
}
public void SetEmotion(string stateName)
{
if (avatarAnimator == null || !avatarAnimator.enabled || string.IsNullOrEmpty(stateName))
return;
if (availableStates.Contains(stateName))
avatarAnimator.Play(stateName);
}
}