dezhou_client/wb_unity_pro/Assets/Scripts/LuaHelper/LuaUIHelper.cs

446 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using LuaInterface;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
public class LuaUIHelper : MonoBehaviour
{
#region 消息提示
private float messageDuration = 2f; // 单条消息显示时间
private float appearDuration = 0.3f; // 出现动画时间
private float disappearDuration = 0.5f; // 消失动画时间
private float startYPosition = -100f; // 起始Y位置底部
private float moveSpeed = 8f; // 位置移动速度
private float spacingMultiplier = 1.2f; // 间距倍数(基于消息高度)
private GameObject msgPrefab;
private Stack<MessageItem> msgPool = new Stack<MessageItem>();
private List<MessageItem> activeMessages = new List<MessageItem>();
private float messageHeight = 60f; // 消息预制体的高度(运行时获取)
private bool isInitialized = false;
// 消息全部消失时的回调
private LuaFunction onAllMessagesDisappeared;
// 初始化消息预制体,并设置消息全部消失时的回调
public void SetMsgPrefab(GameObject prefab, LuaFunction onMsgEnd)
{
msgPrefab = prefab;
// 设置回调
onAllMessagesDisappeared = onMsgEnd;
// 获取预制体的高度
RectTransform prefabRect = prefab.GetComponent<RectTransform>();
if (prefabRect != null)
{
messageHeight = prefabRect.rect.height;
}
// 获取Image组件的高度如果有
Image image = prefab.GetComponent<Image>();
if (image != null)
{
RectTransform imageRect = image.GetComponent<RectTransform>();
messageHeight = imageRect.rect.height;
}
isInitialized = true;
}
// 显示消息
public void ShowInfo(string strMsg)
{
if (!isInitialized)
{
return;
}
MessageItem msg = GetMessageItem();
msg.Initialize(strMsg, this, messageDuration);
// 新消息总是在列表的开头索引0表示最底部
activeMessages.Insert(0, msg);
// 更新所有消息的目标位置
UpdateAllTargetPositions();
// 开始显示新消息
StartCoroutine(msg.Show());
}
// 从池中获取消息项
private MessageItem GetMessageItem()
{
MessageItem msg;
if (msgPool.Count > 0)
{
msg = msgPool.Pop();
msg.gameObject.SetActive(true);
}
else
{
GameObject go = Instantiate(msgPrefab, msgPrefab.transform.parent, false);
msg = new MessageItem(go);
}
return msg;
}
// 计算消息之间的间距
private float GetSpacing()
{
return messageHeight * spacingMultiplier;
}
// 更新所有消息的目标位置
private void UpdateAllTargetPositions()
{
float spacing = GetSpacing();
// 列表索引0是最底部的消息最新
// 列表索引越大位置越高(越靠上)
for (int i = 0; i < activeMessages.Count; i++)
{
// 第i条消息的位置 = 起始位置 + (从底部算起的索引 * 间距)
float targetY = startYPosition + (i * spacing);
activeMessages[i].SetTargetY(targetY);
}
}
private void Update()
{
// 更新所有活跃消息的位置
for (int i = 0; i < activeMessages.Count; i++)
{
var msg = activeMessages[i];
// 更新消息的生命周期
msg.UpdateMessage(Time.deltaTime);
// 如果消息应该消失,开始消失动画
if (msg.ShouldDisappear() && msg.currentState != MessageState.Disappearing)
{
StartCoroutine(HandleMessageDisappear(msg));
}
// 更新消息位置(平滑移动)
if (msg.currentState == MessageState.Active || msg.currentState == MessageState.Appearing)
{
msg.UpdatePosition(Time.deltaTime * moveSpeed);
}
}
}
// 处理消息消失
private IEnumerator HandleMessageDisappear(MessageItem msg)
{
// 开始消失动画
yield return StartCoroutine(msg.Disappear());
// 从活跃列表中移除
if (activeMessages.Contains(msg))
{
activeMessages.Remove(msg);
// 回收消息到对象池
ReturnToPool(msg);
// 重新计算剩余消息的位置
UpdateAllTargetPositions();
// 检查是否所有消息都消失了
CheckAllMessagesDisappeared();
}
}
// 检查是否所有消息都消失了
private void CheckAllMessagesDisappeared()
{
if (activeMessages.Count == 0 && onAllMessagesDisappeared != null)
{
onAllMessagesDisappeared.Call();
}
}
// 回收消息项到池中
private void ReturnToPool(MessageItem msg)
{
msg.gameObject.SetActive(false);
msg.Reset();
msgPool.Push(msg);
}
// 消息状态枚举
private enum MessageState
{
WaitingToShow, // 等待显示
Appearing, // 出现中
Active, // 活跃中
Disappearing // 消失中
}
// 消息项类
private class MessageItem
{
public GameObject gameObject;
public RectTransform rect;
public Text text;
public CanvasGroup canvasGroup;
public Image backgroundImage; // 背景图片
private LuaUIHelper manager;
private MessageState _currentState = MessageState.WaitingToShow;
public MessageState currentState => _currentState;
private float currentY; // 当前Y位置
private float targetY; // 目标Y位置
private float appearProgress; // 出现进度
private float lifeTime; // 生命周期计时器
private float maxLifeTime; // 最大生命周期
public MessageItem(GameObject go)
{
gameObject = go;
rect = go.GetComponent<RectTransform>();
text = go.transform.GetChild(0).GetComponent<Text>();
// 获取背景图片
backgroundImage = go.GetComponent<Image>();
// 添加或获取CanvasGroup
canvasGroup = go.GetComponent<CanvasGroup>();
if (canvasGroup == null)
canvasGroup = go.AddComponent<CanvasGroup>();
}
// 初始化消息
public void Initialize(string message, LuaUIHelper manager, float duration)
{
this.manager = manager;
this.maxLifeTime = duration;
text.text = message;
// 重置状态
_currentState = MessageState.WaitingToShow;
appearProgress = 0f;
lifeTime = 0f;
// 新消息从屏幕外更底部开始
float spacing = manager.GetSpacing();
currentY = manager.startYPosition - spacing - 50f;
rect.anchoredPosition = new Vector2(0, currentY);
canvasGroup.alpha = 0f;
// 确保消息可见
if (backgroundImage != null)
{
backgroundImage.enabled = true;
}
gameObject.SetActive(true);
}
// 设置目标Y位置
public void SetTargetY(float y)
{
targetY = y;
}
// 更新消息生命周期
public void UpdateMessage(float deltaTime)
{
if (_currentState == MessageState.Active)
{
lifeTime += deltaTime;
}
}
// 检查是否应该消失
public bool ShouldDisappear()
{
return _currentState == MessageState.Active && lifeTime >= maxLifeTime;
}
// 显示消息
public IEnumerator Show()
{
_currentState = MessageState.Appearing;
// 出现动画:从下方滑入并淡入
float timer = 0f;
float startY = currentY;
while (timer < manager.appearDuration)
{
timer += Time.deltaTime;
appearProgress = timer / manager.appearDuration;
// 缓动函数EaseOutCubic
float easedProgress = 1f - Mathf.Pow(1f - appearProgress, 3);
// 位置动画(从下方滑入)
float newY = Mathf.Lerp(startY, targetY, easedProgress);
currentY = newY;
rect.anchoredPosition = new Vector2(0, newY);
// 透明度动画
canvasGroup.alpha = Mathf.Lerp(0f, 1f, easedProgress);
yield return null;
}
// 进入活跃状态
_currentState = MessageState.Active;
currentY = targetY;
rect.anchoredPosition = new Vector2(0, targetY);
canvasGroup.alpha = 1f;
// 重置生命周期计时器
lifeTime = 0f;
}
// 消失动画
public IEnumerator Disappear()
{
_currentState = MessageState.Disappearing;
// 向上淡出消失
float timer = 0f;
float startY = currentY;
float disappearY = startY + 50f; // 向上移动消失
while (timer < manager.disappearDuration)
{
timer += Time.deltaTime;
float progress = timer / manager.disappearDuration;
// 缓动函数EaseInCubic
float easedProgress = Mathf.Pow(progress, 3);
// 位置动画(向上移动)
float newY = Mathf.Lerp(startY, disappearY, easedProgress);
rect.anchoredPosition = new Vector2(0, newY);
// 透明度动画
canvasGroup.alpha = Mathf.Lerp(1f, 0f, easedProgress);
yield return null;
}
// 完全消失
canvasGroup.alpha = 0f;
rect.anchoredPosition = new Vector2(0, disappearY);
}
// 更新位置(平滑移动到目标位置)
public void UpdatePosition(float speed)
{
if ((_currentState == MessageState.Active || _currentState == MessageState.Appearing) &&
Mathf.Abs(currentY - targetY) > 0.1f)
{
currentY = Mathf.Lerp(currentY, targetY, speed);
rect.anchoredPosition = new Vector2(0, currentY);
}
else if (_currentState == MessageState.Active)
{
currentY = targetY;
rect.anchoredPosition = new Vector2(0, targetY);
}
}
// 重置状态
public void Reset()
{
_currentState = MessageState.WaitingToShow;
appearProgress = 0f;
lifeTime = 0f;
canvasGroup.alpha = 0f;
// 重置位置到初始位置
rect.anchoredPosition = Vector2.zero;
}
}
#endregion
public Text[] GetAllText(GameObject go)
{
Text[] allTexts = go.GetComponentsInChildren<Text>(true);
return allTexts.Where(text => !text.CompareTag("untext")).ToArray();
}
public void DelayAction(float floTime, LuaFunction func)
{
StartCoroutine(_delayAction(floTime, func));
}
IEnumerator _delayAction(float floTime, LuaFunction func)
{
yield return new WaitForSeconds(floTime);
func.Call();
}
public void AddButtonClick(Button button, LuaFunction func)
{
if (button == null || func == null) return;
button.onClick.AddListener(() =>
{
func.Call();
});
}
public void AddButtonClickWithGameObject(Button button, LuaFunction func)
{
if (button == null || func == null) return;
GameObject go = button.gameObject;
button.onClick.AddListener(() =>
{
func.Call(go);
});
}
public void AddButtonClick(Button button, LuaFunction func, int index)
{
if (button == null || func == null) return;
button.onClick.AddListener(() =>
{
func.Call(index);
});
}
public void AddButtonClick(Button button, LuaFunction func, LuaTable ta)
{
if (button == null || func == null) return;
button.onClick.AddListener(() =>
{
func.Call(ta);
});
}
public float GetAnimatorAormalizedTime(Animator a, bool boo)
{
AnimatorStateInfo infor = a.GetCurrentAnimatorStateInfo(0);
if (boo)
{
return infor.normalizedTime;
}
return infor.normalizedTime % 1;
}
public float GetAnimtorTotalTime(Animator a)
{
AnimatorStateInfo infor = a.GetCurrentAnimatorStateInfo(0);
return infor.length;
}
public bool GetAnimatorIsName(Animator a, string strName)
{
return a.GetCurrentAnimatorStateInfo(0).IsName(strName);
}
public void SetGameObjectLastSibling(GameObject go)
{
go.transform.SetAsLastSibling();
}
}