Ver.0.3.0.33

This commit is contained in:
2025-07-08 08:32:46 +00:00
parent 99f4dd67c2
commit 0ad5e29917
6831 changed files with 695623 additions and 234455 deletions
-55
View File
@@ -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