Ver.0.3.0.33
This commit is contained in:
@@ -1,55 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class Actor : MonoBehaviour
|
||||
{
|
||||
private Animator animator;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// 自动获取 Animator 组件
|
||||
animator = GetComponent<Animator>();
|
||||
if (animator == null)
|
||||
{
|
||||
Debug.LogError("Animator component not found on actor.");
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayAnimation(string animationName)
|
||||
{
|
||||
if (animator != null)
|
||||
{
|
||||
animator.Play(animationName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Animator not found on actor.");
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializeAtSlot(Transform slot)
|
||||
{
|
||||
if (slot != null)
|
||||
{
|
||||
transform.position = slot.position;
|
||||
transform.rotation = slot.rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Slot transform is null.");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAnimationState(string stateName)
|
||||
{
|
||||
if (animator != null)
|
||||
{
|
||||
animator.SetTrigger(stateName);
|
||||
Debug.Log("Trigger"+stateName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Animator not found on actor.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 62e221e22720bec40b69d4bf463b3db2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 265fce8ae27049f6adda23e9dc325ee2
|
||||
timeCreated: 1748247925
|
||||
@@ -0,0 +1,111 @@
|
||||
using System.Collections;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Utility;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色基类
|
||||
/// 有Sprite实现和Animator实现
|
||||
/// </summary>
|
||||
public abstract class AbsActor : MonoBehaviour
|
||||
{
|
||||
public string ActorName { get; private set; }
|
||||
public string SlotName { get; private set; }
|
||||
protected SpriteRenderer spriteRenderer;
|
||||
|
||||
public virtual void Init(string actorName, ActorSlot slot)
|
||||
{
|
||||
ActorName = actorName;
|
||||
spriteRenderer = GetComponent<SpriteRenderer>();
|
||||
SetSlot(slot);
|
||||
}
|
||||
|
||||
public virtual void Show()
|
||||
{
|
||||
spriteRenderer.SetAlpha(1);
|
||||
}
|
||||
|
||||
public virtual void Hide()
|
||||
{
|
||||
spriteRenderer.SetAlpha(0);
|
||||
}
|
||||
|
||||
public void SetSlot(ActorSlot slot)
|
||||
{
|
||||
transform.position = slot.Position;
|
||||
SlotName = slot.slotName;
|
||||
spriteRenderer.sortingOrder = slot.sortingOrder;
|
||||
spriteRenderer.sortingLayerID = slot.sortingLayer;
|
||||
}
|
||||
|
||||
public virtual IEnumerator FadeInAsync(float duration)
|
||||
{
|
||||
yield return spriteRenderer.DOFade(1, duration).WaitForCompletion();
|
||||
}
|
||||
|
||||
public virtual IEnumerator FadeOutAsync(float duration)
|
||||
{
|
||||
yield return spriteRenderer.DOFade(0, duration).WaitForCompletion();
|
||||
}
|
||||
|
||||
public abstract void ChangeState(string stateName);
|
||||
|
||||
public virtual IEnumerator ChangeStateAsync(string stateName)
|
||||
{
|
||||
ChangeState(stateName);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
// 工厂类
|
||||
public class ActorFactory
|
||||
{
|
||||
private readonly Transform _actorRoot;
|
||||
private readonly GameObject _actorAnimaPrefab;
|
||||
private readonly GameObject _spriteActorPrefab;
|
||||
|
||||
public ActorFactory(Transform actorRoot)
|
||||
{
|
||||
_actorRoot = actorRoot;
|
||||
_actorAnimaPrefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.ActorPrefabName);
|
||||
_spriteActorPrefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.SpriteActorPrefabName);
|
||||
}
|
||||
|
||||
public AbsActor CreateActor(string actorName, ActorSlot slot, ActorType actorType)
|
||||
{
|
||||
return actorType switch
|
||||
{
|
||||
ActorType.Sprite => CreateSpriteActor(actorName, slot),
|
||||
ActorType.Anima => CreateActorAnima(actorName, slot),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
private AbsActor CreateSpriteActor(string actorName, ActorSlot slot)
|
||||
{
|
||||
var actor = Object.Instantiate(_spriteActorPrefab, _actorRoot);
|
||||
actor.name = actorName;
|
||||
var actorAnima = actor.GetComponent<AbsActor>();
|
||||
actorAnima.Init(actorName, slot);
|
||||
return actorAnima;
|
||||
}
|
||||
|
||||
private AbsActor CreateActorAnima(string actorName, ActorSlot slot)
|
||||
{
|
||||
var actor = Object.Instantiate(_actorAnimaPrefab, _actorRoot);
|
||||
actor.name = actorName;
|
||||
var actorAnima = actor.GetComponent<AbsActor>();
|
||||
actorAnima.Init(actorName, slot);
|
||||
return actorAnima;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ActorType
|
||||
{
|
||||
Sprite,
|
||||
Anima
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abafcaa803b94362b24d01fc4ad8fdc0
|
||||
timeCreated: 1748007750
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Utility;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class ActorAnima : AbsActor
|
||||
{
|
||||
private Animator _animator;
|
||||
|
||||
public override void Init(string actorName, ActorSlot slot)
|
||||
{
|
||||
_animator = GetComponent<Animator>();
|
||||
// 设置基本信息
|
||||
base.Init(actorName, slot);
|
||||
// 获取Controller
|
||||
var controller = ResourceKit.LoadAssetSync<RuntimeAnimatorController>($"Animation/{actorName}");
|
||||
_animator.runtimeAnimatorController = controller;
|
||||
spriteRenderer.SetAlpha(0);
|
||||
}
|
||||
|
||||
public override void Show()
|
||||
{
|
||||
spriteRenderer.SetAlpha(1);
|
||||
}
|
||||
|
||||
public override void Hide()
|
||||
{
|
||||
spriteRenderer.SetAlpha(0);
|
||||
}
|
||||
|
||||
public override void ChangeState(string animaName)
|
||||
{
|
||||
_animator.Play(animaName);
|
||||
}
|
||||
|
||||
public override IEnumerator ChangeStateAsync(string animaName)
|
||||
{
|
||||
_animator.Play(animaName);
|
||||
|
||||
// 等待一帧确保动画状态切换完成
|
||||
yield return null;
|
||||
|
||||
// 等待直到动画状态名称匹配
|
||||
while (!_animator.GetCurrentAnimatorStateInfo(0).IsName(animaName))
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
var info = _animator.GetCurrentAnimatorStateInfo(0);
|
||||
yield return new WaitForSeconds(info.length);
|
||||
}
|
||||
|
||||
public override IEnumerator FadeInAsync(float duration)
|
||||
{
|
||||
yield return spriteRenderer.DOFade(1, duration).WaitForCompletion();
|
||||
}
|
||||
|
||||
public override IEnumerator FadeOutAsync(float duration)
|
||||
{
|
||||
yield return spriteRenderer.DOFade(0, duration).WaitForCompletion();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d6d97f9ccd644ac9865acc0e8bcad66
|
||||
timeCreated: 1747908611
|
||||
@@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AibisDream.Kit;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class ActorManager : Singleton<ActorManager>
|
||||
{
|
||||
#region 索引
|
||||
|
||||
private Transform _actorRoot;
|
||||
private Dictionary<string, ActorSlot> _slotDict;
|
||||
private Dictionary<string, AbsActor> _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);
|
||||
}
|
||||
}
|
||||
|
||||
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<string, ActorSlot>();
|
||||
foreach (var child in transform.Find("Slots").GetComponentsInChildren<ActorSlot>())
|
||||
{
|
||||
_slotDict[child.slotName] = child;
|
||||
}
|
||||
|
||||
_actorDict = new Dictionary<string, AbsActor>();
|
||||
_actorFactory = new ActorFactory(_actorRoot);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public void InitAllDefault()
|
||||
{
|
||||
InitRefs();
|
||||
DestroyEditorTemp();
|
||||
foreach (var slot in _slotDict.Values)
|
||||
{
|
||||
var actor = InitActor(slot.defaultActorName, slot.slotName, slot.defaultActorType);
|
||||
actor.Show();
|
||||
}
|
||||
}
|
||||
#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>(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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3700d4c1c99441a7979e423de3700aad
|
||||
timeCreated: 1747907449
|
||||
@@ -0,0 +1,18 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class ActorSlot : MonoBehaviour
|
||||
{
|
||||
// 保存层级信息
|
||||
public string slotName;
|
||||
[HideInInspector] public int sortingLayer;
|
||||
[HideInInspector] public int sortingOrder;
|
||||
|
||||
public Vector3 Position => transform.position;
|
||||
|
||||
[Header("设置初始角色")] [SerializeField] public bool hasDefaultActor;
|
||||
[SerializeField] public ActorType defaultActorType;
|
||||
[SerializeField] public string defaultActorName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1988b7c536404a3d89fd441651bd40ea
|
||||
timeCreated: 1748005913
|
||||
@@ -0,0 +1,22 @@
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class SpriteActor : AbsActor
|
||||
{
|
||||
public override void Init(string actorName, ActorSlot slot)
|
||||
{
|
||||
base.Init(actorName, slot);
|
||||
// 赋值
|
||||
spriteRenderer.sprite = ResourceKit.LoadAssetSync<Sprite>($"Sprite/{ActorName}[Idle]");
|
||||
spriteRenderer.SetAlpha(0);
|
||||
}
|
||||
|
||||
public override void ChangeState(string stateName)
|
||||
{
|
||||
spriteRenderer.sprite = ResourceKit.LoadAssetSync<Sprite>($"Sprite/{ActorName}[{stateName}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6bb1b847b634daca8351126b7e717d6
|
||||
timeCreated: 1748009914
|
||||
@@ -1,128 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AibisDream.Utility;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
public class ActorManager : MonoBehaviour
|
||||
{
|
||||
[Header("Actors")]
|
||||
private List<Actor> actors = new List<Actor>();
|
||||
|
||||
[Header("Slots")]
|
||||
public List<Transform> slotList = new List<Transform>(); // 用于在编辑器中设置插槽
|
||||
private Dictionary<string, Transform> slots = new Dictionary<string, Transform>();
|
||||
|
||||
[YarnCommand("fade_in_actor")]
|
||||
public IEnumerator FadeInActorByName(string actorName, float duration)
|
||||
{
|
||||
var actor = actors.Find(a => a.name == actorName);
|
||||
if (actor != null)
|
||||
{
|
||||
yield return StartCoroutine(FadeActor(actor.GetComponent<SpriteRenderer>(), 0f, 1f, duration));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Actor with name {actorName} not found.");
|
||||
}
|
||||
}
|
||||
|
||||
[YarnCommand("fade_out_actor")]
|
||||
public IEnumerator FadeOutActorByName(string actorName, float duration)
|
||||
{
|
||||
var actor = actors.Find(a => a.name == actorName);
|
||||
if (actor != null)
|
||||
{
|
||||
yield return StartCoroutine(FadeActor(actor.GetComponent<SpriteRenderer>(), 1f, 0f, duration));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Actor with name {actorName} not found.");
|
||||
}
|
||||
}
|
||||
|
||||
[YarnCommand("play_actor_animation")]
|
||||
public void PlayActorAnimation(string actorName, string animationName)
|
||||
{
|
||||
var actor = actors.Find(a => a.name == actorName);
|
||||
if (actor != null)
|
||||
{
|
||||
actor.SetAnimationState(animationName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Actor with name {actorName} not found.");
|
||||
}
|
||||
}
|
||||
|
||||
[YarnCommand("initialize_actor_at_slot")]
|
||||
public void InitializeActorAtSlot(string actorName, string slotName)
|
||||
{
|
||||
var prefab = Resources.Load<GameObject>($"CharacterPrefab/{actorName}");
|
||||
if (prefab != null && slots.TryGetValue(slotName, out var slot))
|
||||
{
|
||||
var actorInstance = Instantiate(prefab, slot.position, slot.rotation,this.transform);
|
||||
actorInstance.name = actorName; // 去掉 "(Clone)" 后缀
|
||||
var actor = actorInstance.GetComponent<Actor>();
|
||||
if (actor != null)
|
||||
{
|
||||
actors.Add(actor);
|
||||
actor.InitializeAtSlot(slot);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Actor prefab with name {actorName} not found or slot with name {slotName} not found.");
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator FadeActor(SpriteRenderer actor, float startAlpha, float endAlpha, float duration)
|
||||
{
|
||||
float elapsedTime = 0f;
|
||||
Color color = actor.color;
|
||||
|
||||
while (elapsedTime < duration)
|
||||
{
|
||||
elapsedTime += Time.deltaTime;
|
||||
float alpha = Mathf.Lerp(startAlpha, endAlpha, elapsedTime / duration);
|
||||
actor.color = new Color(color.r, color.g, color.b, alpha);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
actor.color = new Color(color.r, color.g, color.b, endAlpha);
|
||||
}
|
||||
|
||||
private void SetActorAlphaZero(SpriteRenderer actor)
|
||||
{
|
||||
actor.SetAlpha(0);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
InitializeSlots();
|
||||
HideAllActors();
|
||||
}
|
||||
|
||||
private void InitializeSlots()
|
||||
{
|
||||
foreach (var slot in slotList)
|
||||
{
|
||||
if (slot != null)
|
||||
{
|
||||
slots[slot.name] = slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HideAllActors()
|
||||
{
|
||||
foreach (var actor in actors)
|
||||
{
|
||||
var spriteRenderer = actor.GetComponent<SpriteRenderer>();
|
||||
if (spriteRenderer != null)
|
||||
{
|
||||
spriteRenderer.color = new Color(spriteRenderer.color.r, spriteRenderer.color.g, spriteRenderer.color.b, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40a5ab0dc89da0f469155caebeaf7383
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05c60ad3522046feb71377fb4c2dda93
|
||||
timeCreated: 1748421539
|
||||
@@ -0,0 +1,28 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public abstract class AbsScenePart : MonoBehaviour
|
||||
{
|
||||
protected TimesOfDay curTime;
|
||||
protected Weather curWeather;
|
||||
|
||||
public abstract void Init(TimesOfDay time, Weather weather = Weather.Sunny);
|
||||
public abstract void OnTimeChange(TimesOfDay time);
|
||||
public abstract void OnWeatherChange(Weather weather);
|
||||
}
|
||||
|
||||
public enum TimesOfDay
|
||||
{
|
||||
Day,
|
||||
Evening,
|
||||
Night
|
||||
}
|
||||
|
||||
public enum Weather
|
||||
{
|
||||
Sunny,
|
||||
Rainy,
|
||||
Snowy
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 564063c8ed384a93a8f3fa85e305f4f9
|
||||
timeCreated: 1748421829
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class ActiveScenePart : AbsScenePart
|
||||
{
|
||||
[SerializeField] private ActivePartAsset[] activePartAssets;
|
||||
|
||||
public override void Init(TimesOfDay time, Weather weather = Weather.Sunny)
|
||||
{
|
||||
curWeather = weather;
|
||||
OnTimeChange(time);
|
||||
}
|
||||
|
||||
public override void OnTimeChange(TimesOfDay time)
|
||||
{
|
||||
curTime = time;
|
||||
|
||||
var timeArray = activePartAssets.Where(item => item.time == time).ToArray();
|
||||
if (timeArray.Length == 0) return;
|
||||
var res = timeArray.DefaultIfEmpty(timeArray[0]).First(item => item.weather == curWeather);
|
||||
gameObject.SetActive(res.active);
|
||||
}
|
||||
|
||||
public override void OnWeatherChange(Weather weather)
|
||||
{
|
||||
curWeather = weather;
|
||||
|
||||
var weatherArray = activePartAssets.Where(item => item.weather == weather).ToArray();
|
||||
if (weatherArray.Length == 0) return;
|
||||
var res = weatherArray.DefaultIfEmpty(weatherArray[0]).First(item => item.time == curTime);
|
||||
gameObject.SetActive(res.active);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct ActivePartAsset
|
||||
{
|
||||
public TimesOfDay time;
|
||||
public Weather weather;
|
||||
public bool active;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5c2ec05c92e467fa6d0c368b76ee7a0
|
||||
timeCreated: 1748426931
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class AnimatorScenePart : AbsScenePart
|
||||
{
|
||||
private Animator _animator;
|
||||
|
||||
public override void Init(TimesOfDay timesOfDay, Weather weather = Weather.Sunny)
|
||||
{
|
||||
_animator = GetComponent<Animator>();
|
||||
|
||||
curWeather = weather;
|
||||
OnTimeChange(timesOfDay);
|
||||
}
|
||||
|
||||
public override void OnTimeChange(TimesOfDay time)
|
||||
{
|
||||
curTime = time;
|
||||
ResetTriggers();
|
||||
_animator.SetTrigger(time.ToString());
|
||||
}
|
||||
|
||||
public override void OnWeatherChange(Weather weather)
|
||||
{
|
||||
curWeather = weather;
|
||||
ResetTriggers();
|
||||
_animator.SetTrigger(weather.ToString());
|
||||
}
|
||||
|
||||
private void ResetTriggers()
|
||||
{
|
||||
foreach (var timeStr in Enum.GetNames(typeof(TimesOfDay)))
|
||||
{
|
||||
_animator.ResetTrigger(timeStr);
|
||||
}
|
||||
|
||||
foreach (var weatherStr in Enum.GetNames(typeof(Weather)))
|
||||
{
|
||||
_animator.ResetTrigger(weatherStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd3df946f8804e1f89c2228e449c0d91
|
||||
timeCreated: 1748424891
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using AibisDream.Kit;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class EnvironmentManager : Singleton<EnvironmentManager>
|
||||
{
|
||||
public bool initOnAwake = true;
|
||||
public TimesOfDay defaultTime;
|
||||
public Weather defaultWeather;
|
||||
|
||||
private AbsScenePart[] _absSceneParts;
|
||||
|
||||
public override void OnSingletonInit()
|
||||
{
|
||||
if (initOnAwake)
|
||||
{
|
||||
InitEnvironment(defaultTime, defaultWeather);
|
||||
}
|
||||
}
|
||||
|
||||
public void InitEnvironment(TimesOfDay timeOfDay, Weather weather)
|
||||
{
|
||||
_absSceneParts = GetComponentsInChildren<AbsScenePart>(true);
|
||||
foreach (var part in _absSceneParts)
|
||||
{
|
||||
part.Init(timeOfDay, weather);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTimeOfDay(TimesOfDay timeOfDay)
|
||||
{
|
||||
foreach (var part in _absSceneParts)
|
||||
{
|
||||
part.OnTimeChange(timeOfDay);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetWeather(Weather weather)
|
||||
{
|
||||
foreach (var part in _absSceneParts)
|
||||
{
|
||||
part.OnWeatherChange(weather);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class EnvironmentYarnCommand
|
||||
{
|
||||
[YarnCommand("init_environment")]
|
||||
public static void InitEnvironment(string timeOfDay, string weatherType = "Sunny")
|
||||
{
|
||||
if (!Enum.TryParse<TimesOfDay>(timeOfDay, out var time))
|
||||
{
|
||||
Debug.Log($"{timeOfDay}是不存在的时间");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Enum.TryParse<Weather>(weatherType, out var weather))
|
||||
{
|
||||
Debug.Log($"{weatherType}是不存在的天气");
|
||||
return;
|
||||
}
|
||||
|
||||
EnvironmentManager.Instance.InitEnvironment(time, weather);
|
||||
}
|
||||
|
||||
[YarnCommand("set_time_of_day")]
|
||||
public static void SetTimeOfDay(string timeOfDay)
|
||||
{
|
||||
if (!Enum.TryParse<TimesOfDay>(timeOfDay, out var time))
|
||||
{
|
||||
Debug.Log($"{timeOfDay}是不存在的时间");
|
||||
return;
|
||||
}
|
||||
|
||||
EnvironmentManager.Instance.SetTimeOfDay(time);
|
||||
}
|
||||
|
||||
[YarnCommand("set_weather")]
|
||||
public static void SetWeather(string weatherType)
|
||||
{
|
||||
if (!Enum.TryParse<Weather>(weatherType, out var weather))
|
||||
{
|
||||
Debug.Log($"{weatherType}是不存在的天气");
|
||||
return;
|
||||
}
|
||||
|
||||
EnvironmentManager.Instance.SetWeather(weather);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ce5564f908241b58f1376a5a6eae55e
|
||||
timeCreated: 1748421608
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
[RequireComponent(typeof(Spawner))]
|
||||
public class SpawnScenePart : AbsScenePart
|
||||
{
|
||||
private Spawner _spawner;
|
||||
[SerializeField] private SpawnerPartAsset[] spawnerPartAssets;
|
||||
|
||||
public override void Init(TimesOfDay time, Weather weather = Weather.Sunny)
|
||||
{
|
||||
_spawner = GetComponent<Spawner>();
|
||||
// 处理数据切换
|
||||
curWeather = weather;
|
||||
OnTimeChange(time);
|
||||
// 切换完成后再行初始化
|
||||
_spawner.Init();
|
||||
}
|
||||
|
||||
public override void OnTimeChange(TimesOfDay time)
|
||||
{
|
||||
curTime = time;
|
||||
|
||||
var timeArray = spawnerPartAssets.Where(item => item.time == time).ToArray();
|
||||
if (timeArray.Length == 0) return;
|
||||
var res = timeArray.DefaultIfEmpty(timeArray[0]).First(item => item.weather == curWeather);
|
||||
UpdateSpawner(res.mobileAddressData);
|
||||
}
|
||||
|
||||
public override void OnWeatherChange(Weather weather)
|
||||
{
|
||||
curWeather = weather;
|
||||
|
||||
var weatherArray = spawnerPartAssets.Where(item => item.weather == weather).ToArray();
|
||||
if (weatherArray.Length == 0) return;
|
||||
var res = weatherArray.DefaultIfEmpty(weatherArray[0]).First(item => item.time == curTime);
|
||||
UpdateSpawner(res.mobileAddressData);
|
||||
}
|
||||
|
||||
private void UpdateSpawner(AddressArray[] addressArrays)
|
||||
{
|
||||
// 先把addressArray转为字典
|
||||
var dict = addressArrays.ToDictionary(addressArray => addressArray.itemName);
|
||||
// 处理Spawner
|
||||
var newData = _spawner.mobileObjectDatas.Select(item => UpdateSpawnerData(item, dict)).ToArray();
|
||||
_spawner.mobileObjectDatas = newData;
|
||||
// 处理下面的初始化物体
|
||||
var initObjects = GetComponentsInChildren<AbsMobileObject>();
|
||||
foreach (var initObject in initObjects)
|
||||
{
|
||||
initObject.mobileObjectData = UpdateSpawnerData(initObject.mobileObjectData, dict);
|
||||
}
|
||||
}
|
||||
|
||||
private MobileObjectData UpdateSpawnerData(MobileObjectData mobileObjectData,
|
||||
Dictionary<string, AddressArray> addressDict)
|
||||
{
|
||||
if (addressDict.TryGetValue(mobileObjectData.itemName, out var partAsset))
|
||||
{
|
||||
mobileObjectData.assetAddressArray = partAsset.assetAddressArray;
|
||||
}
|
||||
|
||||
return mobileObjectData;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct SpawnerPartAsset
|
||||
{
|
||||
public TimesOfDay time;
|
||||
public Weather weather;
|
||||
public AddressArray[] mobileAddressData;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct AddressArray
|
||||
{
|
||||
public string itemName;
|
||||
public string[] assetAddressArray;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2973f622187142fd9230396685c3fdf6
|
||||
timeCreated: 1749392263
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
[RequireComponent(typeof(SpriteRenderer))]
|
||||
public class SpriteScenePart : AbsScenePart
|
||||
{
|
||||
[SerializeField] private SpritePartAsset[] spritePartAssets;
|
||||
private SpriteRenderer _spriteRenderer;
|
||||
|
||||
public override void Init(TimesOfDay time, Weather weather = Weather.Sunny)
|
||||
{
|
||||
_spriteRenderer = GetComponent<SpriteRenderer>();
|
||||
|
||||
curWeather = weather;
|
||||
OnTimeChange(time);
|
||||
}
|
||||
|
||||
public override void OnTimeChange(TimesOfDay time)
|
||||
{
|
||||
curTime = time;
|
||||
|
||||
var timeArray = spritePartAssets.Where(item => item.time == time).ToArray();
|
||||
if (timeArray.Length == 0) return;
|
||||
var res = timeArray.DefaultIfEmpty(timeArray[0]).First(item => item.weather == curWeather);
|
||||
_spriteRenderer.sprite = res.sprite;
|
||||
}
|
||||
|
||||
public override void OnWeatherChange(Weather weather)
|
||||
{
|
||||
curWeather = weather;
|
||||
|
||||
var weatherArray = spritePartAssets.Where(item => item.weather == weather).ToArray();
|
||||
if (weatherArray.Length == 0) return;
|
||||
var res = weatherArray.DefaultIfEmpty(weatherArray[0]).First(item => item.time == curTime);
|
||||
_spriteRenderer.sprite = res.sprite;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct SpritePartAsset
|
||||
{
|
||||
public TimesOfDay time;
|
||||
public Weather weather;
|
||||
public Sprite sprite;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fef000300a1b45f0ae3e23d3a3d9b81f
|
||||
timeCreated: 1748421946
|
||||
@@ -1,92 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
public class EnvironmentManager : MonoBehaviour
|
||||
{
|
||||
[Header("Time of Day Objects")]
|
||||
public List<GameObject> dayObjects;
|
||||
public List<GameObject> nightObjects;
|
||||
public List<GameObject> midnightObjects;
|
||||
|
||||
[Header("Weather Effects")]
|
||||
public GameObject snowEffect;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// 设置默认状态
|
||||
SetTimeOfDay(TimeOfDay.Day);
|
||||
SetWeather(false);
|
||||
}
|
||||
|
||||
[YarnCommand("set_time_of_day")]
|
||||
public void SetTimeOfDayCommand(string timeOfDay)
|
||||
{
|
||||
timeOfDay = timeOfDay.ToLower();
|
||||
if (timeOfDay == "day" && dayObjects.Count > 0)
|
||||
{
|
||||
SetTimeOfDay(TimeOfDay.Day);
|
||||
}
|
||||
else if (timeOfDay == "night" && nightObjects.Count > 0)
|
||||
{
|
||||
SetTimeOfDay(TimeOfDay.Night);
|
||||
}
|
||||
else if (timeOfDay == "midnight" && midnightObjects.Count > 0)
|
||||
{
|
||||
SetTimeOfDay(TimeOfDay.Midnight);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Invalid or unavailable time of day: {timeOfDay}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTimeOfDay(TimeOfDay timeOfDay)
|
||||
{
|
||||
if (dayObjects.Count > 0)
|
||||
{
|
||||
foreach (var obj in dayObjects)
|
||||
{
|
||||
obj.SetActive(timeOfDay == TimeOfDay.Day);
|
||||
}
|
||||
}
|
||||
|
||||
if (nightObjects.Count > 0)
|
||||
{
|
||||
foreach (var obj in nightObjects)
|
||||
{
|
||||
obj.SetActive(timeOfDay == TimeOfDay.Night);
|
||||
}
|
||||
}
|
||||
|
||||
if (midnightObjects.Count > 0)
|
||||
{
|
||||
foreach (var obj in midnightObjects)
|
||||
{
|
||||
obj.SetActive(timeOfDay == TimeOfDay.Midnight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[YarnCommand("set_weather")]
|
||||
public void SetWeatherCommand(string weatherType)
|
||||
{
|
||||
bool isSnowing = weatherType.ToLower() == "snow";
|
||||
SetWeather(isSnowing);
|
||||
}
|
||||
|
||||
public void SetWeather(bool isSnowing)
|
||||
{
|
||||
if (snowEffect != null)
|
||||
{
|
||||
snowEffect.SetActive(isSnowing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum TimeOfDay
|
||||
{
|
||||
Day,
|
||||
Night,
|
||||
Midnight
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ebc4f12b48436f4985f9bf4ee8b92b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5682792eece34ae8905f894cfc22b1a6
|
||||
timeCreated: 1749715620
|
||||
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Kit;
|
||||
using Cinemachine;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class SubwayCenter : Singleton<SubwayCenter>
|
||||
{
|
||||
#region 部分索引
|
||||
|
||||
public BubbleSlotGroup subwaySlots;
|
||||
public BubbleSlotGroup tvSlots;
|
||||
|
||||
public CinemachineVirtualCamera subwayCam;
|
||||
public CinemachineVirtualCamera tvCam;
|
||||
|
||||
public PlayableDirector arriveStation;
|
||||
|
||||
public static StateMachine<OutSideState> StateMachine { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public override void OnSingletonInit()
|
||||
{
|
||||
CameraKit.Instance.RegisterCamera(CameraEnum.Subway, subwayCam);
|
||||
CameraKit.Instance.RegisterCamera(CameraEnum.SubwayTV, tvCam);
|
||||
|
||||
StateMachine = new StateMachine<OutSideState>(CreateState);
|
||||
StartCoroutine(StateMachine.Init(OutSideState.Subway));
|
||||
}
|
||||
|
||||
public override void OnSingletonDestroy()
|
||||
{
|
||||
CameraKit.Instance.UnRegisterCamera(CameraEnum.SubwayTV);
|
||||
CameraKit.Instance.UnRegisterCamera(CameraEnum.Subway);
|
||||
}
|
||||
|
||||
private static IState<OutSideState> CreateState(OutSideState nextState, string arg = "")
|
||||
{
|
||||
IState<OutSideState> res = nextState switch
|
||||
{
|
||||
OutSideState.Subway => new SubwayState(),
|
||||
OutSideState.SubwayTV => new SubwayTVState(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(nextState), nextState, null)
|
||||
};
|
||||
|
||||
res.SetArgs(arg);
|
||||
return res;
|
||||
}
|
||||
|
||||
public IEnumerator ArriveAtStation()
|
||||
{
|
||||
arriveStation.Play();
|
||||
yield return new WaitForSeconds((float) arriveStation.playableAsset.duration);
|
||||
}
|
||||
}
|
||||
|
||||
public struct SubwayState : IState<OutSideState>
|
||||
{
|
||||
public OutSideState GetState => OutSideState.Subway;
|
||||
|
||||
public IEnumerator Enter()
|
||||
{
|
||||
yield return CameraKit.Instance.SwitchCamera(CameraEnum.Subway);
|
||||
BubbleGroup.Instance.LoadBubbles(SubwayCenter.Instance.subwaySlots.CollectData());
|
||||
}
|
||||
}
|
||||
|
||||
public struct SubwayTVState : IState<OutSideState>
|
||||
{
|
||||
public OutSideState GetState => OutSideState.SubwayTV;
|
||||
|
||||
public IEnumerator Enter()
|
||||
{
|
||||
yield return CameraKit.Instance.SwitchCamera(CameraEnum.SubwayTV);
|
||||
// 要加载气泡吗?
|
||||
BubbleGroup.Instance.LoadBubbles(SubwayCenter.Instance.tvSlots.CollectData());
|
||||
}
|
||||
}
|
||||
|
||||
public enum OutSideState
|
||||
{
|
||||
Subway,
|
||||
SubwayTV
|
||||
}
|
||||
|
||||
public static class SubwayYarnCommand
|
||||
{
|
||||
[YarnCommand("switch_outside_to")]
|
||||
public static IEnumerator SwitchOutsideTo(string targetStateStr)
|
||||
{
|
||||
if (!Enum.TryParse(targetStateStr, out OutSideState targetState))
|
||||
{
|
||||
Debug.Log($"{targetStateStr}不在OutSideState枚举中");
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return SubwayCenter.StateMachine.SwitchState(targetState);
|
||||
}
|
||||
|
||||
[YarnCommand("arrive_at_station")]
|
||||
public static IEnumerator ArriveAtStation()
|
||||
{
|
||||
return SubwayCenter.Instance.ArriveAtStation();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ceb74596ad944c8e9c599f00a445c8a3
|
||||
timeCreated: 1749715671
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 184f2f4770474c03bad3231908325f6f
|
||||
timeCreated: 1748496668
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class AbsMobileObject : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public MobileObjectData mobileObjectData;
|
||||
private Vector3 _initPos;
|
||||
|
||||
public bool IsActive { get; private set; }
|
||||
public float ExistTime { get; private set; }
|
||||
public float Speed { get; private set; }
|
||||
public event Action<AbsMobileObject> OnDisposed;
|
||||
|
||||
public virtual void Init()
|
||||
{
|
||||
transform.position += new Vector3(mobileObjectData.offset.x, mobileObjectData.offset.y, 0);
|
||||
_initPos = transform.position;
|
||||
gameObject.name = mobileObjectData.itemName;
|
||||
IsActive = true;
|
||||
Speed = RandomSpeed();
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
public void Init(MobileObjectData data)
|
||||
{
|
||||
mobileObjectData = data;
|
||||
Init();
|
||||
}
|
||||
|
||||
protected string RandomSelectAddress()
|
||||
{
|
||||
return mobileObjectData.assetAddressArray[
|
||||
UnityEngine.Random.Range(0, mobileObjectData.assetAddressArray.Length)];
|
||||
}
|
||||
|
||||
protected float RandomSpeed()
|
||||
{
|
||||
return UnityEngine.Random.Range(mobileObjectData.speed.x, mobileObjectData.speed.y);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// 移动
|
||||
if (IsActive)
|
||||
{
|
||||
var posDelta = mobileObjectData.direction.normalized * (Speed * Time.deltaTime);
|
||||
transform.position += new Vector3(posDelta.x, posDelta.y, 0);
|
||||
|
||||
ExistTime += Time.deltaTime;
|
||||
|
||||
if (IsReachEnd())
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsReachEnd()
|
||||
{
|
||||
if (mobileObjectData.isDistanceMode)
|
||||
{
|
||||
return mobileObjectData.existDistance <= Vector3.Distance(transform.position, _initPos);
|
||||
}
|
||||
|
||||
return mobileObjectData.existTime <= ExistTime;
|
||||
}
|
||||
|
||||
protected virtual void Dispose()
|
||||
{
|
||||
IsActive = false;
|
||||
ExistTime = 0;
|
||||
_initPos = default;
|
||||
mobileObjectData = default;
|
||||
gameObject.name = "Empty";
|
||||
gameObject.SetActive(false);
|
||||
// 回收
|
||||
OnDisposed?.Invoke(this);
|
||||
OnDisposed = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ceb451ae0d94ff1b8de5a1e25433ee7
|
||||
timeCreated: 1748505616
|
||||
@@ -0,0 +1,33 @@
|
||||
using AibisDream.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public class AnimaMobileObject : AbsMobileObject
|
||||
{
|
||||
private Animator _animator;
|
||||
private SpriteRenderer _spriteRenderer;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
_animator = GetComponent<Animator>();
|
||||
var controller = ResourceKit.LoadAssetSync<RuntimeAnimatorController>(RandomSelectAddress());
|
||||
_animator.runtimeAnimatorController = controller;
|
||||
|
||||
_spriteRenderer = GetComponent<SpriteRenderer>();
|
||||
_spriteRenderer.sortingLayerID = mobileObjectData.sortingLayerId;
|
||||
_spriteRenderer.sortingOrder = mobileObjectData.sortingOrder;
|
||||
|
||||
_spriteRenderer.flipX = mobileObjectData.flipX;
|
||||
_spriteRenderer.flipY = mobileObjectData.flipY;
|
||||
}
|
||||
|
||||
protected override void Dispose()
|
||||
{
|
||||
_animator.runtimeAnimatorController = null;
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01207e7e956b485d92b0112694380ce2
|
||||
timeCreated: 1748513686
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AibisDream.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class BatchSpawner : Spawner
|
||||
{
|
||||
[SerializeField] private Vector2 batchInterval;
|
||||
private bool _isSpawning;
|
||||
|
||||
protected override ISelector<MobileObjectData> CreateSelector(IEnumerable<MobileObjectData> datas)
|
||||
{
|
||||
return new BatchSelector<MobileObjectData>(datas, item => item.weight);
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
if (_isSpawning) return;
|
||||
|
||||
curInterval += Time.deltaTime;
|
||||
// 按时间间隔生成物体
|
||||
if (curInterval >= targetInterval)
|
||||
{
|
||||
Spawn();
|
||||
curInterval = 0;
|
||||
targetInterval = Random.Range(intervalRange.x, intervalRange.y);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Spawn()
|
||||
{
|
||||
StartCoroutine(SpawnCoroutine());
|
||||
}
|
||||
|
||||
private IEnumerator SpawnCoroutine()
|
||||
{
|
||||
_isSpawning = true;
|
||||
for (var i = 0; i < selector.Count; i++)
|
||||
{
|
||||
// 生成物体
|
||||
var data = selector.Select();
|
||||
var mobileObj = factory.CreateMobileObject(data);
|
||||
mobileObjects.Add(mobileObj);
|
||||
// 销毁时同样记录
|
||||
mobileObj.OnDisposed += o => mobileObjects.Remove(o);
|
||||
|
||||
var interval = Random.Range(batchInterval.x, batchInterval.y);
|
||||
yield return new WaitForSeconds(interval);
|
||||
}
|
||||
|
||||
_isSpawning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f8dbbddeadc43158db470f2e9bb1a09
|
||||
timeCreated: 1749011126
|
||||
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Kit;
|
||||
using AibisDream.Utility;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class MobileObjectFactory
|
||||
{
|
||||
private readonly Transform _spawner;
|
||||
|
||||
private readonly SimpleObjectPool<AbsMobileObject> _animaPool;
|
||||
private readonly SimpleObjectPool<AbsMobileObject> _spritePool;
|
||||
private readonly SimpleObjectPool<AbsMobileObject> _objectPool;
|
||||
|
||||
public MobileObjectFactory(Transform spawner)
|
||||
{
|
||||
_spawner = spawner;
|
||||
|
||||
var anima = ResourceKit.LoadAssetSync<GameObject>(ConstRef.MobileAnima);
|
||||
_animaPool =
|
||||
new SimpleObjectPool<AbsMobileObject>(() => InstantiateObject(anima, spawner), ResetObject);
|
||||
|
||||
var sprite = ResourceKit.LoadAssetSync<GameObject>(ConstRef.MobileSprite);
|
||||
_spritePool =
|
||||
new SimpleObjectPool<AbsMobileObject>(() => InstantiateObject(sprite, spawner), ResetObject);
|
||||
|
||||
var objectPrefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.MobileObject);
|
||||
_objectPool =
|
||||
new SimpleObjectPool<AbsMobileObject>(() => InstantiateObject(objectPrefab, spawner), ResetObject);
|
||||
}
|
||||
|
||||
public void AddRecycleMobiles(AbsMobileObject[] unRecycledObjects)
|
||||
{
|
||||
foreach (var mobileObject in unRecycledObjects)
|
||||
{
|
||||
mobileObject.OnDisposed += mobileObject switch
|
||||
{
|
||||
AnimaMobileObject => o => _animaPool.Recycle(o),
|
||||
SpriteMobileObject => o => _spritePool.Recycle(o),
|
||||
_ => o => _objectPool.Recycle(o)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private AbsMobileObject InstantiateObject(GameObject prefab, Transform spawner)
|
||||
{
|
||||
var obj = Object.Instantiate(prefab, spawner).transform;
|
||||
obj.transform.position = spawner.position;
|
||||
return obj.GetComponent<AbsMobileObject>();
|
||||
}
|
||||
|
||||
private void ResetObject(AbsMobileObject mobileObject)
|
||||
{
|
||||
mobileObject.transform.position = _spawner.position;
|
||||
}
|
||||
|
||||
public AbsMobileObject CreateMobileObject(MobileObjectData data)
|
||||
{
|
||||
var pool = data.mobileType switch
|
||||
{
|
||||
MobileType.Anima => _animaPool,
|
||||
MobileType.Sprite => _spritePool,
|
||||
MobileType.Object => _objectPool,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
var res = pool.Allocate();
|
||||
res.Init(data);
|
||||
res.OnDisposed += o => pool.Recycle(o);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct MobileObjectData
|
||||
{
|
||||
public string itemName;
|
||||
public Vector2 direction;
|
||||
public Vector2 speed;
|
||||
public MobileType mobileType;
|
||||
public string[] assetAddressArray;
|
||||
public Vector2 offset;
|
||||
[CustomSortingLayer] public int sortingLayerId;
|
||||
public int sortingOrder;
|
||||
[HideInInspector] public bool isDistanceMode;
|
||||
[HideInInspector] public float existTime;
|
||||
[HideInInspector] public float existDistance;
|
||||
|
||||
public int weight;
|
||||
|
||||
public bool flipX;
|
||||
public bool flipY;
|
||||
}
|
||||
|
||||
public enum MobileType
|
||||
{
|
||||
Anima,
|
||||
Sprite,
|
||||
Object
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d97a5ef89af4eb784a3ada4f261281d
|
||||
timeCreated: 1748505658
|
||||
@@ -0,0 +1,27 @@
|
||||
using AibisDream.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class PrefabMobileObject : AbsMobileObject
|
||||
{
|
||||
private GameObject _childObject;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
var spriteAsset = ResourceKit.LoadAssetSync<GameObject>(RandomSelectAddress());
|
||||
|
||||
_childObject = Instantiate(spriteAsset, transform);
|
||||
var scaleX = mobileObjectData.flipX ? -1 : 1;
|
||||
var scaleY = mobileObjectData.flipY ? -1 : 1;
|
||||
_childObject.transform.localScale = new Vector3(scaleX, scaleY, 1);
|
||||
}
|
||||
|
||||
protected override void Dispose()
|
||||
{
|
||||
Destroy(_childObject);
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d940da74d8ad4d06bd6b93aac28f13c9
|
||||
timeCreated: 1748592649
|
||||
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AibisDream.Framework;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class Spawner : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public MobileObjectData[] mobileObjectDatas;
|
||||
|
||||
[SerializeField] public bool playOnAwake;
|
||||
[SerializeField] private InitMode initMode;
|
||||
|
||||
[SerializeField] private bool isDistanceMode = true;
|
||||
[SerializeField] private float existTime;
|
||||
[SerializeField] private float existDistance;
|
||||
|
||||
[SerializeField] protected Vector2 intervalRange;
|
||||
|
||||
protected ISelector<MobileObjectData> selector;
|
||||
protected MobileObjectFactory factory;
|
||||
|
||||
public readonly List<AbsMobileObject> mobileObjects = new();
|
||||
|
||||
protected float curInterval;
|
||||
protected float targetInterval;
|
||||
|
||||
protected bool isSpawning;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (playOnAwake)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
// 先为Data赋一些公共值
|
||||
var newMobileDatas = SetPublicVariable();
|
||||
// 处理随机权重
|
||||
selector = CreateSelector(newMobileDatas);
|
||||
// 创建工厂
|
||||
factory = new MobileObjectFactory(transform);
|
||||
// 收集初始物体
|
||||
CollectDefaultMobiles();
|
||||
// 生成第一个物体
|
||||
targetInterval = Random.Range(intervalRange.x, intervalRange.y);
|
||||
SpawnFirst();
|
||||
}
|
||||
|
||||
protected void SpawnFirst()
|
||||
{
|
||||
switch (initMode)
|
||||
{
|
||||
case InitMode.Immediate:
|
||||
curInterval = 0;
|
||||
Spawn();
|
||||
break;
|
||||
case InitMode.Random:
|
||||
curInterval = Random.Range(0, targetInterval);
|
||||
break;
|
||||
case InitMode.Next:
|
||||
curInterval = 0;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
isSpawning = true;
|
||||
}
|
||||
|
||||
protected virtual ISelector<MobileObjectData> CreateSelector(IEnumerable<MobileObjectData> datas)
|
||||
{
|
||||
return new RandomSelector<MobileObjectData>(datas, data => data.weight);
|
||||
}
|
||||
|
||||
private List<MobileObjectData> SetPublicVariable()
|
||||
{
|
||||
var res = new List<MobileObjectData>();
|
||||
foreach (var temp in mobileObjectDatas)
|
||||
{
|
||||
var dataItem = temp;
|
||||
dataItem.isDistanceMode = isDistanceMode;
|
||||
dataItem.existTime = existTime;
|
||||
dataItem.existDistance = existDistance;
|
||||
|
||||
res.Add(dataItem);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private void CollectDefaultMobiles()
|
||||
{
|
||||
// 为工厂收集一些初始物体
|
||||
var initObjects = GetComponentsInChildren<AbsMobileObject>();
|
||||
factory.AddRecycleMobiles(initObjects);
|
||||
foreach (var initObject in initObjects)
|
||||
{
|
||||
// 赋公共值
|
||||
initObject.mobileObjectData.isDistanceMode = isDistanceMode;
|
||||
initObject.mobileObjectData.existTime = existTime;
|
||||
initObject.mobileObjectData.existDistance = existDistance;
|
||||
// 启动
|
||||
initObject.Init();
|
||||
mobileObjects.Add(initObject);
|
||||
initObject.OnDisposed += o => mobileObjects.Remove(o);
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (isSpawning)
|
||||
{
|
||||
OnUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnUpdate()
|
||||
{
|
||||
curInterval += Time.deltaTime;
|
||||
// 按时间间隔生成物体
|
||||
if (curInterval >= targetInterval)
|
||||
{
|
||||
Spawn();
|
||||
curInterval = 0;
|
||||
targetInterval = Random.Range(intervalRange.x, intervalRange.y);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Spawn()
|
||||
{
|
||||
// 生成物体
|
||||
var data = selector.Select();
|
||||
var mobileObj = factory.CreateMobileObject(data);
|
||||
mobileObjects.Add(mobileObj);
|
||||
// 销毁时同样记录
|
||||
mobileObj.OnDisposed += o => mobileObjects.Remove(o);
|
||||
}
|
||||
}
|
||||
|
||||
public enum InitMode
|
||||
{
|
||||
Immediate,
|
||||
Random,
|
||||
Next
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36a82fb65d2d45a8a6ce391835134c22
|
||||
timeCreated: 1748499575
|
||||
@@ -0,0 +1,31 @@
|
||||
using AibisDream.Framework;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
[RequireComponent(typeof(SpriteRenderer))]
|
||||
public class SpriteMobileObject : AbsMobileObject
|
||||
{
|
||||
private SpriteRenderer _spriteRenderer;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
var spriteAsset = ResourceKit.LoadAssetSync<Sprite>(RandomSelectAddress());
|
||||
|
||||
_spriteRenderer = GetComponent<SpriteRenderer>();
|
||||
_spriteRenderer.sprite = spriteAsset;
|
||||
_spriteRenderer.sortingLayerID = mobileObjectData.sortingLayerId;
|
||||
_spriteRenderer.sortingOrder = mobileObjectData.sortingOrder;
|
||||
|
||||
_spriteRenderer.flipX = mobileObjectData.flipX;
|
||||
_spriteRenderer.flipY = mobileObjectData.flipY;
|
||||
}
|
||||
|
||||
protected override void Dispose()
|
||||
{
|
||||
_spriteRenderer.sprite = null;
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74c3f049f89f4a70abbb5147c676bbb1
|
||||
timeCreated: 1748589655
|
||||
Reference in New Issue
Block a user