Implement effect.

This commit is contained in:
2023-02-18 14:51:28 +08:00
parent 6bd32c9aef
commit 900bd7b77a
9 changed files with 194 additions and 7 deletions

View File

@@ -44,6 +44,7 @@ namespace Cryville.Crtr {
EventBus nbus;
InputProxy inputProxy;
Judge judge;
public static EffectManager effectManager;
bool started = false;
static bool initialized;
@@ -160,6 +161,8 @@ namespace Cryville.Crtr {
tbus.ForwardStepByTime(renderDist, step);
tbus.EndGraphicalUpdate();
UnityEngine.Profiling.Profiler.EndSample();
effectManager.Tick(cbus.Time);
}
catch (Exception ex) {
Game.LogException("Game", "An error occured while playing", ex);
@@ -496,6 +499,8 @@ namespace Cryville.Crtr {
if (tbus != null) { tbus.Dispose(); tbus = null; }
if (bbus != null) { bbus.Dispose(); bbus = null; }
if (cbus != null) { cbus.Dispose(); cbus.DisposeAll(); cbus = null; }
effectManager.Dispose();
effectManager = null;
etor = null;
Logger.Log("main", 1, "Game", "Stopped");
}
@@ -638,6 +643,7 @@ namespace Cryville.Crtr {
skin.LoadPdt(dir);
pskin = skin.Root;
pskin.Optimize(etor);
effectManager = new EffectManager(pskin);
}
#endregion
}

View File

@@ -0,0 +1,59 @@
using Cryville.Common.Buffers;
using System.Collections.Generic;
namespace Cryville.Crtr {
public class EffectGroup {
public EffectDefinition Definition { get; private set; }
readonly EffectPool _pool;
class EffectPool : ObjectPool<EffectInstance> {
readonly List<EffectInstance> _instances
= new List<EffectInstance>();
readonly EffectGroup _group;
public EffectPool(EffectGroup group) : base(256) {
_group = group;
}
protected override EffectInstance Construct() {
var result = new EffectInstance(_group.Definition);
_instances.Add(result);
return result;
}
public void DisposeAll() {
foreach (var i in _instances) i.Dispose();
}
}
readonly Dictionary<float, EffectInstance> _instances
= new Dictionary<float, EffectInstance>();
readonly List<EffectInstance> _endQueue
= new List<EffectInstance>();
public EffectGroup(EffectDefinition def) {
Definition = def;
_pool = new EffectPool(this);
}
double _time;
public void Tick(double time) {
_time = time;
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);
}
}
public void Emit(float index) {
EffectInstance instance;
if (!_instances.TryGetValue(index, out instance)) {
_instances.Add(index, instance = _pool.Rent());
}
instance.Index = index;
instance.OnEmit(_time);
var i = _endQueue.BinarySearch(instance);
if (i < 0) i = ~i;
_endQueue.Insert(i, instance);
}
public void Dispose() {
_pool.DisposeAll();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d0d27f9b4383b3445a2a27bfe94173a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,66 @@
using Cryville.Common;
using Cryville.Crtr.Components;
using System;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
namespace Cryville.Crtr {
public class EffectInstance : ISkinnableGroup, IComparable<EffectInstance> {
readonly EffectDefinition _def;
readonly SkinContainer _skinContainer;
public Transform RootTransform { get; private set; }
public EffectInstance(EffectDefinition def) {
_def = def;
_skinContainer = new SkinContainer(_def.elements);
RootTransform = new GameObject("effect:" + GetHashCode().ToString(CultureInfo.InvariantCulture)).transform;
SkinContext = new SkinContext(RootTransform);
ChartPlayer.etor.ContextCascadeInsertBlock();
_skinContainer.MatchStatic(this);
ChartPlayer.etor.ContextCascadeDiscardBlock();
foreach (var i in RootTransform.GetComponentsInChildren<SkinComponent>())
i.Init();
_indexSrc = new PropSrc.Float(() => Index);
_durationOp = new PropOp.Float(v => _duration = v);
}
public float Index { get; set; }
static readonly int _var_index = IdentifierManager.SharedInstance.Request("index");
readonly PropSrc _indexSrc;
double _startTime;
float _duration;
readonly PropOp _durationOp;
public double EndTime { get { return _startTime + _duration; } }
public void OnEmit(double time) {
_startTime = time;
RootTransform.gameObject.SetActive(true);
ChartPlayer.etor.ContextCascadeInsert();
ChartPlayer.etor.ContextCascadeUpdate(_var_index, _indexSrc);
ChartPlayer.etor.Evaluate(_durationOp, _def.duration);
_skinContainer.MatchDynamic(this, 0);
ChartPlayer.etor.ContextCascadeDiscard();
}
public void OnDone() {
RootTransform.gameObject.SetActive(false);
}
public void Dispose() {
GameObject.Destroy(RootTransform.gameObject);
}
public string TypeName { get { throw new InvalidOperationException("Type name undefined"); } }
public SkinContext SkinContext { get; private set; }
public Anchor OpenedAnchor { get { throw new InvalidOperationException("Anchor not supported"); } }
public void PushAnchorEvent(double time, int name) {
throw new InvalidOperationException("Anchor not supported");
}
public void RegisterAnchor(int name) {
throw new InvalidOperationException("Anchor not supported");
}
public bool TryGetAnchorsByName(int name, out IReadOnlyCollection<Anchor> result) {
throw new InvalidOperationException("Anchor not supported");
}
public int CompareTo(EffectInstance other) {
return EndTime.CompareTo(other.EndTime);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f442db34239c47046ba1b6fdae8e1216
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace Cryville.Crtr {
public class EffectManager {
readonly Dictionary<int, EffectGroup> _groups
= new Dictionary<int, EffectGroup>();
public EffectManager(PdtSkin skin) {
foreach (var e in skin.effects) {
_groups.Add(e.Key.Key, new EffectGroup(e.Value));
}
}
public void Tick(double time) {
foreach (var g in _groups) g.Value.Tick(time);
}
public void Emit(int id, float index) {
_groups[id].Emit(index);
}
public void Dispose() {
foreach (var g in _groups) g.Value.Dispose();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 980c0f18a6f491d44a866a85910cb458
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -59,9 +59,6 @@ namespace Cryville.Crtr {
foreach (var e in effects) {
var effect = e.Value;
etor.ContextCascadeInsert();
if (effect.args != null) foreach (var i in effect.args) {
etor.ContextCascadeUpdate(i.Key, PropSrc.Error);
}
etor.Optimize(effect.duration);
effect.elements.Optimize(etor);
etor.ContextCascadeDiscard();
@@ -101,7 +98,6 @@ namespace Cryville.Crtr {
}
public class EffectDefinition {
public Identifier[] args;
public PdtExpression duration;
public SkinElement elements;
}

View File

@@ -98,16 +98,21 @@ namespace Cryville.Crtr {
}
public class EmitEffect : SkinPropertyKey {
public int Name { get; set; }
public EmitEffect() { }
public EmitEffect() {
_op = new PropOp.Float(v => _index = v);
}
public override string ToString() {
return string.Format("@emit {0}", IdentifierManager.SharedInstance.Retrieve(Name));
}
public override bool IsValueRequired { get { return true; } }
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp) {
// TODO
throw new InvalidOperationException("Emitting effect in static context is not allowed");
}
float _index;
readonly PropOp _op;
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, int dl) {
// TODO
ChartPlayer.etor.Evaluate(_op, exp);
ChartPlayer.effectManager.Emit(Name, _index);
}
}
}