using System; using System.Collections; using AibisDream.Framework; using AibisDream.SaveSystem; using AibisDream.Utility; using DG.Tweening; using UnityEngine; using UnityEngine.ResourceManagement.AsyncOperations; using Object = UnityEngine.Object; namespace AibisDream { /// /// 角色基类 /// 有Sprite实现和Animator实现 /// public abstract class AbsActor : MonoBehaviour { protected string _actorName; protected string _slotName; protected ActorType _actorType; protected float _alpha; protected SpriteRenderer spriteRenderer; private Tween _shakeTween; private Vector3 _shakeOrigin; public string ActorName => _actorName; public string SlotName => _slotName; public ActorType ActorType => _actorType; public virtual bool IsReady => true; public void Init(string actorName, ActorSlot slot, ActorType actorType) { _actorName = actorName; _slotName = slot.slotName; _actorType = actorType; _alpha = 0; InitInternal(); SetSlot(slot); } public void InitFromEntry(ActorEntrySnapshotDto entry, ActorSlot slot) { _actorName = entry.actorName; _slotName = entry.slotName; _alpha = entry.alpha; if (!Enum.TryParse(entry.actorType, out _actorType)) { _actorType = ActorType.Anima; } InitInternal(); SetSlot(slot); } protected virtual void InitInternal() { gameObject.name = ActorName; spriteRenderer = GetComponent(); spriteRenderer.SetAlpha(0); } public virtual IEnumerator InitializeAsync() { yield break; } public abstract ActorEntrySnapshotDto CaptureEntry(); public abstract IEnumerator ApplyEntryAsync(ActorEntrySnapshotDto entry); protected void FillBaseEntry(ActorEntrySnapshotDto entry) { entry.actorName = _actorName; entry.slotName = _slotName; entry.actorType = _actorType.ToString(); entry.alpha = _alpha; } protected void ApplyAlphaFromEntry(ActorEntrySnapshotDto entry) { if (entry.alpha <= 0.01f) { Hide(); } else { SetAlpha(Mathf.RoundToInt(entry.alpha)); } } public void Show() { _alpha = 1; spriteRenderer.SetAlpha(1); } public void Hide() { _alpha = 0; spriteRenderer.SetAlpha(0); } public void SetSlot(ActorSlot slot) { StopShake(); transform.position = slot.Position; spriteRenderer.sortingOrder = slot.sortingOrder; spriteRenderer.sortingLayerID = slot.sortingLayer; _slotName = slot.slotName; } /// /// 持续振动角色立绘;再次调用会用新参数替换当前振动。 /// public void StartShake(float strength, float cycleDuration, int vibrato) { StopShake(); strength = Mathf.Max(0.001f, strength); cycleDuration = Mathf.Max(0.05f, cycleDuration); vibrato = Mathf.Max(1, vibrato); _shakeOrigin = transform.position; _shakeTween = transform .DOShakePosition( cycleDuration, new Vector3(strength, strength * 0.35f, 0f), vibrato, 90f, false, false, ShakeRandomnessMode.Full) .SetEase(Ease.Linear) .SetLoops(-1, LoopType.Restart) .SetLink(gameObject, LinkBehaviour.KillOnDestroy); } /// /// 停止振动,并将立绘恢复到开始振动前的位置。 /// public void StopShake() { if (_shakeTween == null) { return; } _shakeTween.Kill(); _shakeTween = null; transform.position = _shakeOrigin; } protected virtual void OnDestroy() { StopShake(); } public IEnumerator FadeInAsync(float duration) { _alpha = 1; yield return spriteRenderer.DOFade(1, duration).WaitForCompletion(); } public IEnumerator FadeOutAsync(float duration) { _alpha = 0; yield return spriteRenderer.DOFade(0, duration).WaitForCompletion(); } public void SetAlpha(int alpha) { _alpha = alpha; spriteRenderer.SetAlpha(alpha); } public abstract void ChangeState(string stateName); public virtual IEnumerator ChangeStateAsync(string stateName) { ChangeState(stateName); yield break; } public virtual void SetTalkingState(bool isTalking) {} public virtual void SetFaceState(string faceName) {} } public class ActorFactory { private readonly Transform _actorRoot; private readonly GameObject _actorAnimaPrefab; private readonly GameObject _spriteActorPrefab; private readonly GameObject _actorAnimaExPrefab; public ActorFactory(Transform actorRoot) { _actorRoot = actorRoot; _actorAnimaPrefab = ResourceKit.LoadAssetSync(ConstRef.ActorPrefabName); _spriteActorPrefab = ResourceKit.LoadAssetSync(ConstRef.SpriteActorPrefabName); _actorAnimaExPrefab = ResourceKit.LoadAssetSync(ConstRef.ActorAnimaExPrefabName); } public AbsActor CreateActor(string actorName, ActorSlot slot, ActorType actorType) { var actor = InstantiateByType(actorType); if (actor) { actor.Init(actorName, slot, actorType); } return actor; } public AbsActor CreateFromEntry(ActorEntrySnapshotDto entry, ActorSlot slot) { if (!Enum.TryParse(entry.actorType, out var actorType)) { actorType = ActorType.Anima; } var actor = InstantiateByType(actorType); if (actor) { actor.InitFromEntry(entry, slot); } return actor; } public IEnumerator CreateActorAsync( string actorName, ActorSlot slot, ActorType actorType, Action onCompleted) { if (actorType != ActorType.FrameAnimation) { onCompleted?.Invoke(CreateActor(actorName, slot, actorType)); yield break; } yield return CreateFrameAnimationActorAsync( actorName, slot, actorType, null, onCompleted); } public IEnumerator CreateFromEntryAsync( ActorEntrySnapshotDto entry, ActorSlot slot, Action onCompleted) { if (!Enum.TryParse(entry.actorType, out var actorType)) { actorType = ActorType.Anima; } if (actorType != ActorType.FrameAnimation) { onCompleted?.Invoke(CreateFromEntry(entry, slot)); yield break; } yield return CreateFrameAnimationActorAsync( entry.actorName, slot, actorType, entry, onCompleted); } private IEnumerator CreateFrameAnimationActorAsync( string actorName, ActorSlot slot, ActorType actorType, ActorEntrySnapshotDto entry, Action onCompleted) { var prefabKey = ConstRef.FrameAnimationActorPrefabName; var handle = ResourceSystem.LoadPersistentAsync(prefabKey); yield return handle; if (handle.Status != AsyncOperationStatus.Succeeded || handle.Result == null) { Debug.LogError( $"[ActorFactory] 角色 '{actorName}' 的帧动画 Prefab 加载失败,key='{prefabKey}'。"); onCompleted?.Invoke(null); yield break; } var instance = Object.Instantiate(handle.Result, _actorRoot); var actor = instance.GetComponent(); if (actor == null) { Debug.LogError( $"[ActorFactory] Prefab '{prefabKey}' 缺少 AbsActor 组件,角色='{actorName}'。"); Object.Destroy(instance); onCompleted?.Invoke(null); yield break; } if (entry == null) { actor.Init(actorName, slot, actorType); } else { actor.InitFromEntry(entry, slot); } yield return actor.InitializeAsync(); if (!actor.IsReady) { Debug.LogError( $"[ActorFactory] 帧动画角色 '{actorName}' 初始化失败,Prefab='{prefabKey}'。"); Object.Destroy(actor.gameObject); onCompleted?.Invoke(null); yield break; } onCompleted?.Invoke(actor); } private AbsActor InstantiateByType(ActorType actorType) { return actorType switch { ActorType.Sprite => Object.Instantiate(_spriteActorPrefab, _actorRoot).GetComponent(), ActorType.Anima => Object.Instantiate(_actorAnimaPrefab, _actorRoot).GetComponent(), ActorType.AnimaEx => Object.Instantiate(_actorAnimaExPrefab, _actorRoot).GetComponent(), _ => null }; } } public enum ActorType { Sprite, Anima, AnimaEx, FrameAnimation = 3 } }