using System.Collections; using System.Collections.Generic; using Ichni.RhythmGame.Beatmap; using UnityEngine; namespace Ichni.RhythmGame { /// /// 包含效果的次级模块 /// public partial class EffectSubmodule : SubmoduleBase { public Dictionary> effectCollection; public EffectSubmodule(GameElement attachedGameElement, EffectSubmodulePreset preset = EffectSubmodulePreset.Default) : base(attachedGameElement) { effectCollection = new Dictionary>(); if (preset == EffectSubmodulePreset.Default) //对于默认的效果次级模块,有Prior、Default、Late三个效果集合 { effectCollection.Add("Prior", new List()); effectCollection.Add("Default", new List()); effectCollection.Add("Late", new List()); } else if (preset == EffectSubmodulePreset.Note) //对于Note的效果次级模块,在Note的不同状态下有独立的效果集合 { effectCollection.Add("Generate", new List()); effectCollection.Add("GeneralJudge", new List()); effectCollection.Add("Holding", new List()); //仅用于Hold effectCollection.Add("Perfect", new List()); effectCollection.Add("Good", new List()); effectCollection.Add("Bad", new List()); effectCollection.Add("Miss", new List()); effectCollection.Add("AfterJudge", new List()); } if (!HaveSameSubmodule) { (attachedGameElement as IHaveEffectSubmodule).effectSubmodule = this; } } public EffectSubmodule(GameElement attachedGameElement, Dictionary> effectList_BM) : base(attachedGameElement) { effectCollection = new Dictionary>(); foreach (var effect in effectList_BM) { List effectList = new List(); foreach (var effectBM in effect.Value) { if (BeatmapContainer_BM.LowPriorityDataTypes.Contains(effectBM.GetType())) // 如果是低优先级数据类型 { (GameManager.instance.beatmapContainer).lowPriorityActions.Add(() => { effectList.Add(effectBM.ConvertToGameType(attachedGameElement)); }); } else { effectList.Add(effectBM.ConvertToGameType(attachedGameElement)); } } effectCollection.Add(effect.Key, effectList); } if (!HaveSameSubmodule) { (attachedGameElement as IHaveEffectSubmodule).effectSubmodule = this; } } } public partial class EffectSubmodule { public override void SaveBM() { matchedBM = new EffectSubmodule_BM(attachedGameElement); } } public partial class EffectSubmodule { public enum EffectSubmodulePreset { Default, Note, } private static Dictionary EffectCollection { get; } = new Dictionary() { { "Bloom", new BloomEffect(1, 2, CustomCurvePresets.Parabolic(1, 0, 1)) }, { "CameraShake", new CameraShakeEffect(1, 50, 1, 1, 1) }, { "ChromaticAberration", new ChromaticAberrationEffect(1, 1, CustomCurvePresets.Parabolic(1, 0, 1)) }, { "Vignette", new VignetteEffect(1, 1, 0.4f, Color.black, CustomCurvePresets.Parabolic(1, 0, 1)) }, { "SetInteger", new SetIntegerEffect("New Variable", 0, false, 0, 1) }, { "EnableControl", new EnableControlEffect(null, "New Variable", 0, false, "") }, { "LowPassFilter", new LowPassFilterEffect(1, 10, CustomCurvePresets.Parabolic(1, 0, 1)) }, { "HighPassFilter", new HighPassFilterEffect(1, 22000, CustomCurvePresets.Parabolic(1, 0, 1)) } }; } public interface IHaveEffectSubmodule { public EffectSubmodule effectSubmodule { get; set; } } namespace Beatmap { public class EffectSubmodule_BM : Submodule_BM { public Dictionary> effectCollection; public EffectSubmodule_BM() { } public EffectSubmodule_BM(GameElement attachedElement) : base(attachedElement) { effectCollection = new Dictionary>(); IHaveEffectSubmodule element = attachedElement as IHaveEffectSubmodule; foreach (var effect in element.effectSubmodule.effectCollection) { List effectList = new List(); foreach (var effectBase in effect.Value) { effectList.Add(effectBase.ConvertToBM()); } effectCollection.Add(effect.Key, effectList); } } public override void ExecuteBM() { attachedElement = GameElement_BM.GetElement(attachedElementGuid); (attachedElement as IHaveEffectSubmodule).effectSubmodule = new EffectSubmodule(attachedElement, effectCollection); } public override void DuplicateBM(GameElement attached) { (attached as IHaveEffectSubmodule).effectSubmodule = new EffectSubmodule(attached, effectCollection); } } } public abstract class EffectBase : IBaseElement { public enum EffectState { Before = -1, Middle = 0, After = 1, Error = 100 } public BaseElement_BM matchedBM { get; set; } public GameElement attachedGameElement; /// /// 效果的持续时间,如果为0则表示瞬间效果 /// public float effectTime; /// /// 是否是瞬间效果 /// public bool isInstantEffect => effectTime <= 0; /// /// 效果的进度百分比 /// public float effectProgressPercent; /// /// 效果当前的状态 /// public EffectState nowEffectState; protected EffectBase() { this.effectTime = 0; this.nowEffectState = EffectState.Before; this.effectProgressPercent = 0; } protected EffectBase(float effectTime) { this.effectTime = effectTime; this.nowEffectState = EffectState.Before; this.effectProgressPercent = 0; } public void SaveBM() { throw new System.NotImplementedException(); } public virtual void UpdateEffect(float triggerTime) { EffectState state = CheckEffectState(triggerTime); float songTime = GameManager.instance.songTime; if (state == EffectState.Before && nowEffectState != EffectState.Before) { nowEffectState = EffectState.Before; effectProgressPercent = 0; Recover(); } else if (state == EffectState.Middle) { if (nowEffectState == EffectState.Before) { PreExecute(); } nowEffectState = EffectState.Middle; effectProgressPercent = (songTime - triggerTime) / effectTime; Execute(); } else if (state == EffectState.After && nowEffectState != EffectState.After) { nowEffectState = EffectState.After; effectProgressPercent = 1; Adjust(); } } protected virtual EffectState CheckEffectState(float triggerTime) { float songTime = GameManager.instance.songTime; if (songTime < triggerTime) { return EffectState.Before; } if (songTime >= triggerTime && songTime <= triggerTime + effectTime) { return EffectState.Middle; } if (songTime > triggerTime + effectTime) { return EffectState.After; } return EffectState.Error; } /// /// 当从Before状态进入Middle状态时,仅在效果的开始时触发一次方法 /// public virtual void PreExecute() { } /// /// 在效果的持续时间内,触发这个方法 /// public virtual void Execute() { } /// /// 如果是非瞬间效果,在效果完成后,触发这个方法; /// 如果是瞬间效果,则此方法即为Execute。原有的Execute方法不被调用。 /// public virtual void Adjust() { } /// /// 如果时间轴回退到效果的触发时间之前,则触发这个方法 /// public virtual void Recover() { } /// /// 如果效果被打断,则触发这个方法 /// public virtual void Disrupt() { } /// /// 转换为存档类 /// /// public abstract EffectBase_BM ConvertToBM(); public void Refresh() { } } namespace Beatmap { public abstract class EffectBase_BM { public float effectTime; public EffectBase_BM() { } public EffectBase_BM(float effectTime) { this.effectTime = effectTime; } /// /// 转换为游戏类 /// /// public abstract EffectBase ConvertToGameType(GameElement attachedGameElement); } } }