Add state-based effect.

This commit is contained in:
2023-03-01 00:37:22 +08:00
parent dfc3e9ca06
commit ba3cbbd64c
4 changed files with 92 additions and 27 deletions

View File

@@ -35,10 +35,14 @@ namespace Cryville.Crtr {
while (_endQueue.Count > 0) { while (_endQueue.Count > 0) {
var item = _endQueue[0]; var item = _endQueue[0];
if (item.EndTime > _time) break; if (item.EndTime > _time) break;
item.OnDone();
_instances.Remove(item.Index);
_pool.Return(item);
_endQueue.RemoveAt(0); _endQueue.RemoveAt(0);
if (item.OnStateDone()) {
QueueInstance(item);
}
else {
_instances.Remove(item.Index);
_pool.Return(item);
}
} }
foreach (var instance in _instances) { foreach (var instance in _instances) {
instance.Value.Tick(time); instance.Value.Tick(time);
@@ -46,18 +50,21 @@ namespace Cryville.Crtr {
} }
public void Emit(float index) { public void Emit(float index) {
EffectInstance instance; EffectInstance instance;
if (_instances.TryGetValue(index, out instance)) { bool flag = _instances.TryGetValue(index, out instance);
var i = _endQueue.BinarySearch(instance); if (!flag) _instances.Add(index, instance = _pool.Rent());
_endQueue.RemoveAt(i);
}
else {
_instances.Add(index, instance = _pool.Rent());
}
instance.Rewind(_time);
instance.Index = index; instance.Index = index;
instance.OnEmit(_time); if (instance.CanEmit()) {
var i2 = ~_endQueue.BinarySearch(instance); if (flag) {
_endQueue.Insert(i2, instance); 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() { public void Dispose() {
_pool.DisposeAll(); _pool.DisposeAll();

View File

@@ -1,5 +1,6 @@
using Cryville.Common; using Cryville.Common;
using Cryville.Crtr.Components; using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@@ -25,6 +26,7 @@ namespace Cryville.Crtr {
_durationOp = new PropOp.Float(v => _duration = v); _durationOp = new PropOp.Float(v => _duration = v);
} }
public void Rewind(double time) { public void Rewind(double time) {
_startTime = time;
foreach (var i in _comps) i.Rewind(time); foreach (var i in _comps) i.Rewind(time);
} }
private float m_index; private float m_index;
@@ -36,6 +38,10 @@ namespace Cryville.Crtr {
_indexSrc.Invalidate(); _indexSrc.Invalidate();
} }
} }
Identifier _currentStateName = Identifier.Empty;
EffectState _currentState;
ChartEvent _ctxev;
ContainerState _ctxstate;
internal static readonly int _VAR_EFFECT_INDEX = IdentifierManager.SharedInstance.Request("effect_index"); internal static readonly int _VAR_EFFECT_INDEX = IdentifierManager.SharedInstance.Request("effect_index");
readonly PropSrc _indexSrc; readonly PropSrc _indexSrc;
double _startTime; double _startTime;
@@ -45,17 +51,47 @@ namespace Cryville.Crtr {
public void Tick(double time) { public void Tick(double time) {
foreach (var i in _comps) i.Tick(_skinContainer, 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) { 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); RootTransform.gameObject.SetActive(true);
ChartPlayer.etor.ContextCascadeInsert(); ChartPlayer.etor.ContextCascadeInsert();
ChartPlayer.etor.ContextCascadeUpdate(_VAR_EFFECT_INDEX, _indexSrc); ChartPlayer.etor.ContextCascadeUpdate(_VAR_EFFECT_INDEX, _indexSrc);
ChartPlayer.etor.Evaluate(_durationOp, _def.duration); ChartPlayer.etor.Evaluate(_durationOp, _currentState.duration);
_skinContainer.MatchDynamic(0); if (emitting) _skinContainer.MatchDynamic(0);
_skinContainer.MatchDynamic(1);
ChartPlayer.etor.ContextCascadeDiscard(); ChartPlayer.etor.ContextCascadeDiscard();
} }
public void OnDone() { public bool OnStateDone() {
RootTransform.gameObject.SetActive(false); 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() { public void Dispose() {
GameObject.Destroy(RootTransform.gameObject); GameObject.Destroy(RootTransform.gameObject);
@@ -63,7 +99,7 @@ namespace Cryville.Crtr {
public string TypeName { get { throw new InvalidOperationException("Type name undefined"); } } public string TypeName { get { throw new InvalidOperationException("Type name undefined"); } }
public SkinContext SkinContext { get; private set; } 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) { public void PushAnchorEvent(double time, int name) {
throw new InvalidOperationException("Anchor not supported"); throw new InvalidOperationException("Anchor not supported");
} }

View File

@@ -101,11 +101,11 @@ namespace Cryville.Crtr {
else throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", IdentifierManager.SharedInstance.Retrieve(name))); else throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", IdentifierManager.SharedInstance.Retrieve(name)));
} }
public ChartEvent ContextEvent { private get; set; } public ChartEvent ContextEvent { get; set; }
public ContainerState ContextState { private get; set; } public ContainerState ContextState { get; set; }
public Transform ContextTransform { private get; set; } public Transform ContextTransform { get; set; }
public Judge ContextJudge { private get; set; } public Judge ContextJudge { get; set; }
public PropSrc ContextSelfValue { private get; set; } public PropSrc ContextSelfValue { get; set; }
readonly Stack<int> ContextCascadeBlocks = new Stack<int>(); readonly Stack<int> ContextCascadeBlocks = new Stack<int>();
public void ContextCascadeInsertBlock() { public void ContextCascadeInsertBlock() {

View File

@@ -60,7 +60,9 @@ namespace Cryville.Crtr {
var effect = e.Value; var effect = e.Value;
etor.ContextCascadeInsert(); etor.ContextCascadeInsert();
etor.ContextCascadeUpdate(EffectInstance._VAR_EFFECT_INDEX, PropSrc.Error); 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); effect.elements.Optimize(etor);
etor.ContextCascadeDiscard(); etor.ContextCascadeDiscard();
} }
@@ -99,10 +101,30 @@ namespace Cryville.Crtr {
} }
public class EffectDefinition { 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<Identifier, EffectState> states = new Dictionary<Identifier, EffectState> {
{ _ident_init, new EffectState() { rewind = _ident_init } }
};
public SkinElement elements; public SkinElement elements;
} }
public class EffectState {
public PdtExpression duration;
public Identifier rewind;
public Identifier next;
}
public class AnimationSpan { public class AnimationSpan {
[ElementList] [ElementList]
public Dictionary<Clip, AnimationSpan> spans public Dictionary<Clip, AnimationSpan> spans