using System; using System.Collections; using System.Collections.Generic; using System.Linq; using AibisDream.Kit; using AibisDream.SaveSystem; using UnityEngine; using Yarn.Unity; namespace AibisDream { public class ActorManager : Singleton { #region 索引 private Transform _actorRoot; private Dictionary _slotDict; private Dictionary _actorDict; private ActorFactory _actorFactory; #endregion public override void OnSingletonInit() { InitRefs(); DestroyEditorTemp(); InitDefaultActor(); } public void DestroyEditorTemp() { foreach (Transform child in _actorRoot) { #if UNITY_EDITOR if (!Application.isPlaying) { DestroyImmediate(child.gameObject); continue; } #endif Destroy(child.gameObject); } _actorDict.Clear(); } private void InitDefaultActor() { foreach (var slot in _slotDict.Values.Where(slot => slot.hasDefaultActor)) { InitActor(slot.defaultActorName, slot.slotName, slot.defaultActorType); } } private void InitRefs() { _actorRoot = transform.Find("ActorRoot"); _slotDict = new Dictionary(); foreach (var child in transform.Find("Slots").GetComponentsInChildren()) { _slotDict[child.slotName] = child; } _actorDict = new Dictionary(); _actorFactory = new ActorFactory(_actorRoot); } public ActorSnapshotDto CaptureSnapshot() { var dto = new ActorSnapshotDto(); foreach (var actor in _actorDict.Values) { var data = actor.actorData; dto.actors.Add(new ActorEntrySnapshotDto { actorName = data.actorName, slotName = data.slotName, actorType = data.actorType.ToString(), stateName = data.stateName, alpha = data.alpha, faceParam = data.faceParam }); } return dto; } public void RestoreSnapshot(ActorSnapshotDto dto) { if (dto?.actors == null) return; DestroyEditorTemp(); foreach (var entry in dto.actors) { if (!Enum.TryParse(entry.actorType, out var actorType)) { actorType = ActorType.Anima; } var actorData = new ActorData { actorName = entry.actorName, slotName = entry.slotName, actorType = actorType, stateName = entry.stateName, alpha = entry.alpha, faceParam = entry.faceParam }; if (!_slotDict.TryGetValue(actorData.slotName, out var slot)) { Debug.LogWarning($"slot {actorData.slotName} 不存在"); continue; } var actor = _actorFactory.CreateActor(actorData, slot); if (actor == null) continue; _actorDict.Add(actorData.actorName, actor); ApplyActorVisualState(actor, actorData); } } private static void ApplyActorVisualState(AbsActor actor, ActorData data) { if (data.alpha <= 0.01f) { actor.Hide(); } else { actor.SetAlpha(Mathf.RoundToInt(data.alpha)); } if (!string.IsNullOrEmpty(data.stateName)) { actor.ChangeState(data.stateName); } } #if UNITY_EDITOR public void InitAllDefault() { InitRefs(); DestroyEditorTemp(); foreach (var slot in _slotDict.Values) { if (!string.IsNullOrEmpty(slot.defaultActorName)) { var actor = InitActor(slot.defaultActorName, slot.slotName, slot.defaultActorType); actor.Show(); } else { Debug.Log($"slot {slot.slotName} 没有默认角色"); } } } #endif public AbsActor InitActor(string actorName, string slotName, ActorType actorType) { var slot = _slotDict[slotName]; var actor = _actorFactory.CreateActor(actorName, slot, actorType); _actorDict.Add(actorName, actor); return actor; } public bool TryFindActor(string actorOrSlot, out AbsActor actor) { if (_actorDict.TryGetValue(actorOrSlot, out actor)) { return true; } actor = _actorDict.Values.FirstOrDefault(item => item.SlotName == actorOrSlot); return actor != null; } public void ChangeSlot(string actorOrSlot, string targetSlot) { if (!_slotDict.TryGetValue(targetSlot, out var targetSlotObj)) return; if (!TryFindActor(actorOrSlot, out var actor)) return; actor.SetSlot(targetSlotObj); } } public static class ActorYarnCommand { private const string ClinicSlotName = "clinic"; [YarnCommand("init_actor")] public static void InitActor(string actorName, string slotName = ClinicSlotName, string actorType = "Anima") { if (Enum.TryParse(actorType, out var actorTypeEnum)) { ActorManager.Instance.InitActor(actorName, slotName, actorTypeEnum); } else { Debug.Log($"Actor类型{actorType}有问题"); } } [YarnCommand("change_actor_state")] public static void PlayAnima(string animaName, string slotOrActorName = ClinicSlotName) { if (ActorManager.Instance.TryFindActor(slotOrActorName, out var actor)) { actor.ChangeState(animaName); } } [YarnCommand("change_actor_state_async")] public static IEnumerator PlayAnimaAsync(string animaName, string slotOrActorName = ClinicSlotName) { if (ActorManager.Instance.TryFindActor(slotOrActorName, out var actor)) { yield return actor.ChangeStateAsync(animaName); } } [YarnCommand("fade_in_actor")] public static IEnumerator ActorFadeIn(string actorName = ClinicSlotName, float duration = 1) { if (ActorManager.Instance.TryFindActor(actorName, out var actor)) { yield return actor.FadeInAsync(duration); } } [YarnCommand("fade_out_actor")] public static IEnumerator ActorFadeOut(string actorName = ClinicSlotName, float duration = 1) { if (ActorManager.Instance.TryFindActor(actorName, out var actor)) { yield return actor.FadeOutAsync(duration); } } [YarnCommand("change_actor_slot")] public static void ChangeSlot(string actorOrSlot, string targetSlot) { ActorManager.Instance.ChangeSlot(actorOrSlot, targetSlot); } [YarnCommand("show_actor")] public static void ShowActor(string actorName = ClinicSlotName) { if (ActorManager.Instance.TryFindActor(actorName, out var actor)) { actor.Show(); } } [YarnCommand("hide_actor")] public static void HideActor(string actorName = ClinicSlotName) { if (ActorManager.Instance.TryFindActor(actorName, out var actor)) { actor.Hide(); } } [YarnCommand("set_actor_face")] public static void SetFaceState(string faceName, string actorName = ClinicSlotName) { if (ActorManager.Instance.TryFindActor(actorName, out var actor)) { actor.SetFaceState(faceName); } } } }