This commit is contained in:
2025-03-07 15:11:58 +08:00
parent 49f07c79d7
commit de883c006c
26 changed files with 486 additions and 201 deletions
@@ -34,16 +34,11 @@ namespace AibisDream.FixSystem
_curArgs = args;
yield return _curState?.Exit();
// 检查当前状态和下一个状态
// if (_curState.GetState == FixState.Clinic && nextState == FixState.BodyModule)
// {
// // 仅在从 Clinic 到 BodyModule 时执行这两行
//
// }
GameLoopManager.Instance?.UpdateFixState(nextState, _curArgs);
_curState = CreateState(nextState, _curArgs);
EnumEventSystem.Global.Send(EventEnum.FixStateSwitch, nextState);
yield return _curState.Enter();
}
@@ -0,0 +1,18 @@
namespace AibisDream.Kit
{
public enum AmbState
{
Main,
Clinic,
Outside,
Footbridge,
Subway,
Head,
Memory,
Eye,
UF,
Body,
Engine,
GearBox
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2cec528d61b846fc9d9791fca8d917ed
timeCreated: 1741259362
@@ -1,13 +0,0 @@
namespace AibisDream.Kit
{
public class AudioKit : Singleton<AudioKit>
{
public AudioPlayer MusicPlayer { get; private set; }
public AudioPlayer VoicePlayer { get; private set; }
public override void OnSingletonInit()
{
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: ff78cd5fd6a74902945f20346bc2036d
timeCreated: 1726662840
@@ -90,17 +90,6 @@ namespace AibisDream
#endregion
#region
public void PlayVoice(string actorName, string voiceName)
{
AudioClip clip = RandomLoadAudioClip(3, $"Audio/{actorName}");
_voiceSource.clip = clip;
_voiceSource.Play();
}
#endregion
#region
[YarnCommand("play_loop_audio")]
@@ -1,26 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace AibisDream.Kit
{
public class AudioPlayer : IPoolable, IPoolType
{
#region
public void OnRecycled()
{
throw new System.NotImplementedException();
}
public bool IsRecycled { get; set; }
public void Recycle2Cache()
{
throw new System.NotImplementedException();
}
#endregion
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5c877314dfb3460d91eef3edfe2786c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,74 @@
using System;
using FMOD.Studio;
using Yarn.Unity;
namespace AibisDream.Kit
{
public static class AudioYarnCommand
{
private static IAudioManager AudioManager => FmodManager.Instance;
[YarnCommand("play_music")]
public static void PlayMusic(string eventName)
{
AudioManager.PlayMusic(eventName);
}
[YarnCommand("stop_music")]
public static void StopMusic(string eventName, string type = null)
{
// 处理停止类型
var mode = type switch
{
"fade" => STOP_MODE.ALLOWFADEOUT,
_ => STOP_MODE.IMMEDIATE
};
AudioManager.StopMusic(eventName, mode);
}
[YarnCommand("set_music_param")]
public static void SetMusicParam(string eventName, string paramName, float paramValue)
{
AudioManager.SetMusicParam(eventName, paramName, paramValue);
}
[YarnCommand("play_sfx")]
public static void PlaySfx(string eventName)
{
AudioManager.PlaySfx(eventName);
}
[YarnCommand("stop_sfx")]
public static void StopSfx(string eventName, string type = null)
{
// 处理停止类型
var mode = type switch
{
"fade" => STOP_MODE.ALLOWFADEOUT,
_ => STOP_MODE.IMMEDIATE
};
AudioManager.StopSfx(eventName, mode);
}
[YarnCommand("set_sfx_param")]
public static void SetSfxParam(string eventName, string paramName, float paramValue)
{
AudioManager.SetSfxParam(eventName, paramName, paramValue);
}
[YarnCommand("change_amb")]
public static void ChangeAmb(string ambState)
{
var realState = Enum.Parse<AmbState>(ambState);
AudioManager.ChangeAmb(realState);
}
[YarnCommand("set_amb_param")]
public static void SetAmbParam(string paramName, float value)
{
AudioManager.SetAmbParam(paramName, value);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0c2c66883a8f4acda0263f7453bd4cd2
timeCreated: 1741257321
@@ -0,0 +1,35 @@
using FMOD.Studio;
using FMODUnity;
namespace AibisDream.Kit
{
public static class FModEx
{
public static bool IsPlaying(this EventInstance instance)
{
if (!instance.isValid()) return false;
instance.getPlaybackState(out var playbackState);
return playbackState == PLAYBACK_STATE.PLAYING;
}
public static PLAYBACK_STATE GetPlayBackState(this EventInstance instance)
{
instance.getPlaybackState(out var playbackState);
return playbackState;
}
public static EventDescription GetDescription(this EventInstance instance)
{
instance.getDescription(out var description);
return description;
}
public static bool IsEventExist(string eventPath)
{
var result = RuntimeManager.StudioSystem.getEvent(eventPath, out _);
return result == FMOD.RESULT.OK;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cf7b32b854524cf9bb65c552e7050830
timeCreated: 1741319049
@@ -1,13 +1,267 @@
using System.Collections;
using System.Collections.Generic;
using AibisDream.FixSystem;
using AibisDream.Framework;
using FMOD;
using FMOD.Studio;
using FMODUnity;
using UnityEngine;
using STOP_MODE = FMOD.Studio.STOP_MODE;
namespace AibisDream.Kit
{
public class FmodManager : Singleton<FmodManager>
public class FmodManager : Singleton<FmodManager>, IAudioManager
{
public EventReference sound;
private const string AmbStateName = "scene";
public string ambPath;
#region Event实例
private EventInstance _ambInstance;
private EventInstance _voiceInstance;
private readonly Dictionary<string, EventInstance> _musicDict = new();
private readonly Dictionary<string, EventInstance> _sfxDict = new();
#endregion
#region
private List<IUnRegister> _removeTrigger;
#endregion
private void Start()
{
// 注册事件
RegisterEvent();
// 启动AMB
InitAmb();
}
private void RegisterEvent()
{
// 语音相关
EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.LineStart, OnLineStart);
EnumEventSystem.Global.Register(DialogEventEnum.LineShown, OnLineShown);
// 场景切换相关
EnumEventSystem.Global.Register<EventEnum, string>(EventEnum.SceneLoad, OnSceneLoad);
EnumEventSystem.Global.Register<EventEnum, FixState>(EventEnum.FixStateSwitch, OnFixStateChange);
EnumEventSystem.Global.Register(EventEnum.SceneUnload, OnSceneUnload);
}
#region AMB相关
private void InitAmb()
{
_ambInstance = RuntimeManager.CreateInstance(FormatEventPath(ambPath));
_ambInstance.start();
}
public void ChangeAmb(AmbState state)
{
_ambInstance.setParameterByName(AmbStateName, (float)state);
}
public void SetAmbParam(string paramName, float value)
{
_ambInstance.setParameterByName(paramName, value);
}
private void OnSceneLoad(string loadingScene)
{
// 场景加载时切换AMB
var state = MatchAmbState(loadingScene);
ChangeAmb(state);
}
private void OnSceneUnload()
{
ChangeAmb(AmbState.Main);
}
private void OnFixStateChange(FixState nextState)
{
// 状态切换时加载
var state = MatchAmbState(nextState);
ChangeAmb(state);
}
#endregion
#region
public void PlayMusic(string eventName)
{
var eventPath = FormatEventPath(eventName);
if (_musicDict.TryGetValue(eventPath, out var oldMusic))
{
oldMusic.start();
}
else
{
var newMusic = RuntimeManager.CreateInstance(eventPath);
_musicDict[eventPath] = newMusic;
newMusic.start();
}
}
public void StopMusic(string eventName, STOP_MODE stopMode)
{
var eventPath = FormatEventPath(eventName);
if (_musicDict.TryGetValue(eventPath, out var oldMusic))
{
oldMusic.stop(stopMode);
oldMusic.release();
_musicDict.Remove(eventPath);
}
}
public void SetMusicParam(string eventName, string param, float paramValue)
{
var eventPath = FormatEventPath(eventName);
if (_musicDict.TryGetValue(eventPath, out var music))
{
music.setParameterByName(param, paramValue);
}
}
#endregion
public void OnLineStart(DialogText dialogText)
{
if (_voiceInstance.IsPlaying())
{
_voiceInstance.stop(STOP_MODE.IMMEDIATE);
_voiceInstance.release();
}
if (string.IsNullOrEmpty(dialogText.actor.voicePath) || FModEx.IsEventExist(dialogText.actor.VoicePath))
{
return;
}
_voiceInstance = RuntimeManager.CreateInstance(dialogText.actor.VoicePath);
_voiceInstance.start();
}
public void OnLineShown()
{
if (_voiceInstance.isValid())
{
_voiceInstance.stop(STOP_MODE.IMMEDIATE);
_voiceInstance.release();
}
}
public void PlaySfx(string eventName)
{
var eventPath = FormatEventPath(eventName);
if (_sfxDict.TryGetValue(eventPath, out var oldSfx))
{
oldSfx.start();
}
else
{
var newSfx = RuntimeManager.CreateInstance(eventPath);
if (newSfx.GetDescription().isOneshot(out var isOneshot) != RESULT.OK || !isOneshot)
{
_sfxDict[eventPath] = newSfx;
}
newSfx.start();
}
}
public void StopSfx(string eventName, STOP_MODE stopMode)
{
var eventPath = FormatEventPath(eventName);
if (_sfxDict.TryGetValue(eventPath, out var oldSfx))
{
oldSfx.stop(stopMode);
oldSfx.release();
_musicDict.Remove(eventPath);
}
}
public void SetSfxParam(string eventName, string paramName, float paramValue)
{
var eventPath = FormatEventPath(eventName);
if (_sfxDict.TryGetValue(eventPath, out var sfx))
{
sfx.setParameterByName(paramName, paramValue);
}
}
#region
private static string FormatEventPath(string eventName)
{
return $"event:/{eventName}";
}
private static AmbState MatchAmbState(string key)
{
return key switch
{
"ExpressFixScene" => AmbState.Clinic,
"ShitouHeadiFixScene" => AmbState.Clinic,
"PeipeiFixScene" => AmbState.Clinic,
"Bridge" => AmbState.Footbridge,
"SkyBridge" => AmbState.Footbridge,
"SubWay" => AmbState.Subway,
"ClinicOut" => AmbState.Outside,
_ => AmbState.Main
};
}
private static AmbState MatchAmbState(FixState fixState)
{
return fixState switch
{
FixState.Clinic => AmbState.Clinic,
FixState.Engine => AmbState.Engine,
FixState.BodyModule => AmbState.Body,
FixState.Gear => AmbState.GearBox,
FixState.UF => AmbState.UF,
FixState.Eye => AmbState.Eye,
FixState.Memory => AmbState.Memory,
_ => AmbState.Main
};
}
#endregion
}
public interface IAudioManager
{
// Yarn音频接口
public void PlayMusic(string eventName);
public void StopMusic(string eventName, STOP_MODE stopMode);
public void SetMusicParam(string eventName, string paramName, float paramValue);
// AMB参数变化
public void ChangeAmb(AmbState state);
public void SetAmbParam(string paramName, float value);
// 语音相关
public void OnLineStart(DialogText dialogText);
public void OnLineShown();
// 交互相关
public void PlaySfx(string eventName);
public void StopSfx(string eventName, STOP_MODE stopMode);
public void SetSfxParam(string eventName, string paramName, float paramValue);
}
public class AudioData : IData
{
public string ambState;
public List<string> sfxNames = new();
public List<string> musicNames = new();
public void Load()
{
throw new System.NotImplementedException();
}
}
}
@@ -46,6 +46,19 @@ namespace AibisDream.Kit
{
return string.IsNullOrEmpty(nameColor) ? cn : $"<color={nameColor}>{cn}</color>";
}
public string VoicePath
{
get
{
if (!voicePath.StartsWith("event:/"))
{
return "event:/" + voicePath;
}
return voicePath;
}
}
}
public enum ActorRole
+4 -1
View File
@@ -11,13 +11,16 @@ namespace AibisDream
PlugOut,
OpenScreen,
CloseScreen,
SceneLoad,
SceneUnload,
FixStateSwitch,
Menu
}
public enum DialogEventEnum
{
LineStart,
LineShowed,
LineShown,
LineEnd,
OptionShow,
OptionSelected
+1
View File
@@ -66,6 +66,7 @@ namespace AibisDream
_loadHandle = Addressables.LoadSceneAsync(_sceneToLoad, LoadSceneMode.Additive);
yield return _loadHandle;
EnumEventSystem.Global.Send(EventEnum.SceneLoad, _sceneToLoad);
_currentScene.Value = _sceneToLoad;
_isLoading = false;
}
@@ -26,7 +26,8 @@ public class LineInteraction : MonoBehaviour
{
// 初始状态不激活
actorGroup.SetActive(false);
scissorSpriteRenderer.transform.localPosition = new Vector3(12f, openYMin - 3, scissorSpriteRenderer.transform.position.z);
scissorSpriteRenderer.transform.localPosition =
new Vector3(12f, openYMin - 3, scissorSpriteRenderer.transform.position.z);
cutLineSpriteRenderer.enabled = false;
}
@@ -36,10 +37,12 @@ public class LineInteraction : MonoBehaviour
if (!isActive) return;
// 获取鼠标在世界坐标中的位置
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane));
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y,
Camera.main.nearClipPlane));
// 更新剪刀的Y轴位置以跟随鼠标
scissorSpriteRenderer.transform.localPosition = new Vector3(scissorSpriteRenderer.transform.localPosition.x, mousePosition.y, scissorSpriteRenderer.transform.localPosition.z);
scissorSpriteRenderer.transform.localPosition = new Vector3(scissorSpriteRenderer.transform.localPosition.x,
mousePosition.y, scissorSpriteRenderer.transform.localPosition.z);
// 检查Y轴位置并更换Sprite
if (mousePosition.y >= openYMin && mousePosition.y <= openYMax)
@@ -76,12 +79,13 @@ public class LineInteraction : MonoBehaviour
// 淡出剪刀和切割线
scissorSpriteRenderer.DOFade(0f, fadeDuration);
cutLineSpriteRenderer.DOFade(0f, fadeDuration);
yield return new WaitForSeconds(fadeDuration*4);
foreach (SpriteRenderer child in actorGroup.GetComponentsInChildren<SpriteRenderer>())
yield return new WaitForSeconds(fadeDuration * 4);
foreach (SpriteRenderer child in actorGroup.GetComponentsInChildren<SpriteRenderer>())
{
child.DOFade(0f, fadeDuration*2);
child.DOFade(0f, fadeDuration * 2);
}
yield return new WaitForSeconds(fadeDuration*2);
yield return new WaitForSeconds(fadeDuration * 2);
// 销毁GameObject
Destroy(gameObject);
@@ -111,7 +115,7 @@ public class LineInteraction : MonoBehaviour
void ContinueTimeline()
{
AudioManager.RandomPlayInteraction("wire_cut");
timelineDirector.Play();
AudioManager.RandomPlayInteraction("wire_cut");
timelineDirector.Play();
}
}
}
+1 -1
View File
@@ -74,7 +74,7 @@ namespace AibisDream
// 对话相关
_unRegisters.Add(EnumEventSystem.Global.Register<DialogEventEnum, DialogText>(DialogEventEnum.LineStart,
OnLineStart));
_unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineShowed, () => SwitchCursor(nextTalk)));
_unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineShown, () => SwitchCursor(nextTalk)));
_unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.LineEnd, OnLineEnd));
_unRegisters.Add(EnumEventSystem.Global.Register(DialogEventEnum.OptionShow, OnOptionShow));
_unRegisters.Add(
+1 -1
View File
@@ -57,7 +57,7 @@ namespace AibisDream
// 自动跳过的回调很难独立Remove,只能全部清空再注册,下策
_dialogText.onTextShowed.RemoveAllListeners();
_dialogText.onTextShowed.AddListener(() => onTextShowed?.Invoke());
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShowed));
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown));
_nextStep = nextStep;
+1 -1
View File
@@ -105,7 +105,7 @@ namespace AibisDream
_dialogText.onTextShowed.RemoveAllListeners();
_dialogText.onTextShowed.AddListener(() => _nextArray.gameObject.SetActive(true));
_dialogText.onTextShowed.AddListener(() => onTextShowed?.Invoke());
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShowed));
_dialogText.onTextShowed.AddListener(() => EnumEventSystem.Global.Send(DialogEventEnum.LineShown));
_nextStep = nextStep;
@@ -130,7 +130,7 @@ namespace AibisDream
private void OnTextShowed()
{
// 触发事件
EnumEventSystem.Global.Send(DialogEventEnum.LineShowed);
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
// 停止语音
_onTextShowed?.Invoke();