From ba3cbbd64c074f1a13e02da70d6fce60abfe7267 Mon Sep 17 00:00:00 2001 From: PopSlime Date: Wed, 1 Mar 2023 00:37:22 +0800 Subject: [PATCH] Add state-based effect. --- Assets/Cryville/Crtr/EffectGroup.cs | 35 +++++++++++-------- Assets/Cryville/Crtr/EffectInstance.cs | 48 ++++++++++++++++++++++---- Assets/Cryville/Crtr/PdtEvaluator.cs | 10 +++--- Assets/Cryville/Crtr/Skin.cs | 26 ++++++++++++-- 4 files changed, 92 insertions(+), 27 deletions(-) diff --git a/Assets/Cryville/Crtr/EffectGroup.cs b/Assets/Cryville/Crtr/EffectGroup.cs index caa95dd..63107b5 100644 --- a/Assets/Cryville/Crtr/EffectGroup.cs +++ b/Assets/Cryville/Crtr/EffectGroup.cs @@ -35,10 +35,14 @@ namespace Cryville.Crtr { while (_endQueue.Count > 0) { var item = _endQueue[0]; if (item.EndTime > _time) break; - item.OnDone(); - _instances.Remove(item.Index); - _pool.Return(item); _endQueue.RemoveAt(0); + if (item.OnStateDone()) { + QueueInstance(item); + } + else { + _instances.Remove(item.Index); + _pool.Return(item); + } } foreach (var instance in _instances) { instance.Value.Tick(time); @@ -46,18 +50,21 @@ namespace Cryville.Crtr { } public void Emit(float index) { EffectInstance instance; - if (_instances.TryGetValue(index, out instance)) { - var i = _endQueue.BinarySearch(instance); - _endQueue.RemoveAt(i); - } - else { - _instances.Add(index, instance = _pool.Rent()); - } - instance.Rewind(_time); + bool flag = _instances.TryGetValue(index, out instance); + if (!flag) _instances.Add(index, instance = _pool.Rent()); instance.Index = index; - instance.OnEmit(_time); - var i2 = ~_endQueue.BinarySearch(instance); - _endQueue.Insert(i2, instance); + if (instance.CanEmit()) { + if (flag) { + var i = _endQueue.BinarySearch(instance); + _endQueue.RemoveAt(i); + } + instance.OnEmit(_time); + QueueInstance(instance); + } + } + void QueueInstance(EffectInstance i) { + var index = ~_endQueue.BinarySearch(i); + _endQueue.Insert(index, i); } public void Dispose() { _pool.DisposeAll(); diff --git a/Assets/Cryville/Crtr/EffectInstance.cs b/Assets/Cryville/Crtr/EffectInstance.cs index 0afd5df..be69c8a 100644 --- a/Assets/Cryville/Crtr/EffectInstance.cs +++ b/Assets/Cryville/Crtr/EffectInstance.cs @@ -1,5 +1,6 @@ using Cryville.Common; using Cryville.Crtr.Components; +using Cryville.Crtr.Event; using System; using System.Collections.Generic; using System.Globalization; @@ -25,6 +26,7 @@ namespace Cryville.Crtr { _durationOp = new PropOp.Float(v => _duration = v); } public void Rewind(double time) { + _startTime = time; foreach (var i in _comps) i.Rewind(time); } private float m_index; @@ -36,6 +38,10 @@ namespace Cryville.Crtr { _indexSrc.Invalidate(); } } + Identifier _currentStateName = Identifier.Empty; + EffectState _currentState; + ChartEvent _ctxev; + ContainerState _ctxstate; internal static readonly int _VAR_EFFECT_INDEX = IdentifierManager.SharedInstance.Request("effect_index"); readonly PropSrc _indexSrc; double _startTime; @@ -45,17 +51,47 @@ namespace Cryville.Crtr { public void Tick(double time) { foreach (var i in _comps) i.Tick(_skinContainer, time); } + public bool CanEmit() { + return _currentStateName.Key == 0 || _currentState.rewind.Key != 0; + } public void OnEmit(double time) { - _startTime = time; + _ctxev = ChartPlayer.etor.ContextEvent; + _ctxstate = ChartPlayer.etor.ContextState; + if (_currentStateName.Key == 0) { + EnterState(_def.init, time, true); + } + else { + if (_currentState.rewind.Key == 0) throw new InvalidOperationException("Cannot rewind"); + EnterState(_currentState.rewind, time, true); + } + } + void EnterState(Identifier name, double time, bool emitting) { + _currentStateName = name; + _currentState = _def.states[name]; + Rewind(time); RootTransform.gameObject.SetActive(true); ChartPlayer.etor.ContextCascadeInsert(); ChartPlayer.etor.ContextCascadeUpdate(_VAR_EFFECT_INDEX, _indexSrc); - ChartPlayer.etor.Evaluate(_durationOp, _def.duration); - _skinContainer.MatchDynamic(0); + ChartPlayer.etor.Evaluate(_durationOp, _currentState.duration); + if (emitting) _skinContainer.MatchDynamic(0); + _skinContainer.MatchDynamic(1); ChartPlayer.etor.ContextCascadeDiscard(); } - public void OnDone() { - RootTransform.gameObject.SetActive(false); + public bool OnStateDone() { + if (_currentState.next.Key == 0) { + RootTransform.gameObject.SetActive(false); + _currentStateName = Identifier.Empty; + _currentState = null; + return false; + } + else { + ChartPlayer.etor.ContextEvent = _ctxev; + ChartPlayer.etor.ContextState = _ctxstate; + EnterState(_currentState.next, EndTime, false); + ChartPlayer.etor.ContextEvent = null; + ChartPlayer.etor.ContextState = null; + return true; + } } public void Dispose() { GameObject.Destroy(RootTransform.gameObject); @@ -63,7 +99,7 @@ namespace Cryville.Crtr { public string TypeName { get { throw new InvalidOperationException("Type name undefined"); } } public SkinContext SkinContext { get; private set; } - public int OpenedAnchorName { get { throw new InvalidOperationException("Anchor not supported"); } } + public int OpenedAnchorName { get { return _currentStateName.Key; } } public void PushAnchorEvent(double time, int name) { throw new InvalidOperationException("Anchor not supported"); } diff --git a/Assets/Cryville/Crtr/PdtEvaluator.cs b/Assets/Cryville/Crtr/PdtEvaluator.cs index 4b38a4d..4973c20 100644 --- a/Assets/Cryville/Crtr/PdtEvaluator.cs +++ b/Assets/Cryville/Crtr/PdtEvaluator.cs @@ -101,11 +101,11 @@ namespace Cryville.Crtr { else throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", IdentifierManager.SharedInstance.Retrieve(name))); } - public ChartEvent ContextEvent { private get; set; } - public ContainerState ContextState { private get; set; } - public Transform ContextTransform { private get; set; } - public Judge ContextJudge { private get; set; } - public PropSrc ContextSelfValue { private get; set; } + public ChartEvent ContextEvent { get; set; } + public ContainerState ContextState { get; set; } + public Transform ContextTransform { get; set; } + public Judge ContextJudge { get; set; } + public PropSrc ContextSelfValue { get; set; } readonly Stack ContextCascadeBlocks = new Stack(); public void ContextCascadeInsertBlock() { diff --git a/Assets/Cryville/Crtr/Skin.cs b/Assets/Cryville/Crtr/Skin.cs index 5c9c5fa..8eff6de 100644 --- a/Assets/Cryville/Crtr/Skin.cs +++ b/Assets/Cryville/Crtr/Skin.cs @@ -60,7 +60,9 @@ namespace Cryville.Crtr { var effect = e.Value; etor.ContextCascadeInsert(); etor.ContextCascadeUpdate(EffectInstance._VAR_EFFECT_INDEX, PropSrc.Error); - etor.Optimize(effect.duration); + foreach(var s in effect.states) { + etor.Optimize(s.Value.duration); + } effect.elements.Optimize(etor); etor.ContextCascadeDiscard(); } @@ -99,10 +101,30 @@ namespace Cryville.Crtr { } public class EffectDefinition { - public PdtExpression duration; + static Identifier _ident_init = new Identifier("init"); +#pragma warning disable IDE1006 + public PdtExpression duration { + set { + EffectState s; + if (!states.TryGetValue(_ident_init, out s)) + throw new InvalidOperationException("Cannot set duration and states at the same time"); + s.duration = value; + } + } +#pragma warning restore IDE1006 + public Identifier init = _ident_init; + public Dictionary states = new Dictionary { + { _ident_init, new EffectState() { rewind = _ident_init } } + }; public SkinElement elements; } + public class EffectState { + public PdtExpression duration; + public Identifier rewind; + public Identifier next; + } + public class AnimationSpan { [ElementList] public Dictionary spans