From b977edf1dae79ec1798d2c84726b3c72b0a95ea6 Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Fri, 9 Oct 2015 21:24:53 +0200 Subject: [PATCH] Added FlashEffect --- CUE.NET.csproj | 2 + Devices/Keyboard/Effects/AbstractEffect.cs | 37 +++++++ Devices/Keyboard/Effects/FlashEffect.cs | 123 +++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 Devices/Keyboard/Effects/AbstractEffect.cs create mode 100644 Devices/Keyboard/Effects/FlashEffect.cs diff --git a/CUE.NET.csproj b/CUE.NET.csproj index 7d7793d..3932d0e 100644 --- a/CUE.NET.csproj +++ b/CUE.NET.csproj @@ -55,6 +55,8 @@ + + diff --git a/Devices/Keyboard/Effects/AbstractEffect.cs b/Devices/Keyboard/Effects/AbstractEffect.cs new file mode 100644 index 0000000..3b9d0a9 --- /dev/null +++ b/Devices/Keyboard/Effects/AbstractEffect.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Linq; +using CUE.NET.Devices.Keyboard.Brushes; +using CUE.NET.Devices.Keyboard.Keys; + +namespace CUE.NET.Devices.Keyboard.Effects +{ + public abstract class AbstractEffect : IEffect + { + #region Properties & Fields + + public abstract IBrush EffectBrush { get; } + + public IEnumerable KeyList { get; protected set; } + + public bool IsDone { get; protected set; } + + #endregion + + #region Methods + + public void SetTarget(IKeyGroup keyGroup) + { + KeyList = keyGroup.Keys.ToList(); + } + + public abstract void Update(float deltaTime); + + public virtual void OnAttach() + { } + + public virtual void OnDetach() + { } + + #endregion + } +} diff --git a/Devices/Keyboard/Effects/FlashEffect.cs b/Devices/Keyboard/Effects/FlashEffect.cs new file mode 100644 index 0000000..5af00e7 --- /dev/null +++ b/Devices/Keyboard/Effects/FlashEffect.cs @@ -0,0 +1,123 @@ +using System; +using System.Drawing; +using CUE.NET.Devices.Keyboard.Brushes; + +namespace CUE.NET.Devices.Keyboard.Effects +{ + public class FlashEffect : AbstractEffect + { + #region Properties & Fields + + public override IBrush EffectBrush { get; } + + // Settings are close to a synthesizer envelope (sustain is different for consequent naming): https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope + public float Attack { get; set; } = 0.2f; + public float Decay { get; set; } = 0f; + public float Sustain { get; set; } = 0.3f; + public float Release { get; set; } = 0.2f; + + public float SustainValue { get; set; } = 1f; + public float AttackValue { get; set; } = 1f; + + public float Interval { get; set; } = 1f; + + public int Repetitions { get; set; } = 0; + + private ADSRPhase _currentPhase; + private float _currentPhaseValue; + private int _repetitionCount; + + #endregion + + #region Constructors + + public FlashEffect(Color flashColor) + : this(new SolidColorBrush(flashColor)) + { } + + public FlashEffect(IBrush effectBrush) + { + this.EffectBrush = effectBrush; + } + + #endregion + + #region Methods + + public override void Update(float deltaTime) + { + _currentPhaseValue -= deltaTime; + + // Using ifs instead of a switch allows to skip phases with time 0. + + if (_currentPhase == ADSRPhase.Attack) + if (_currentPhaseValue > 0f) + EffectBrush.Opacity = Math.Min(1f, (Attack - _currentPhaseValue) / Attack) * AttackValue; + else + { + _currentPhaseValue = Decay; + _currentPhase = ADSRPhase.Decay; + } + + if (_currentPhase == ADSRPhase.Decay) + if (_currentPhaseValue > 0f) + EffectBrush.Opacity = SustainValue + (Math.Min(1f, _currentPhaseValue / Decay) * (AttackValue - SustainValue)); + else + { + _currentPhaseValue = Sustain; + _currentPhase = ADSRPhase.Sustain; + } + + if (_currentPhase == ADSRPhase.Sustain) + if (_currentPhaseValue > 0f) + EffectBrush.Opacity = SustainValue; + else + { + _currentPhaseValue = Release; + _currentPhase = ADSRPhase.Release; + } + + if (_currentPhase == ADSRPhase.Release) + if (_currentPhaseValue > 0f) + EffectBrush.Opacity = Math.Min(1f, _currentPhaseValue / Release) * SustainValue; + else + { + _currentPhaseValue = Interval; + _currentPhase = ADSRPhase.Pause; + } + + if (_currentPhase == ADSRPhase.Pause) + if (_currentPhaseValue > 0f) + EffectBrush.Opacity = 0f; + else + { + if (++_repetitionCount >= Repetitions && Repetitions > 0) + IsDone = true; + _currentPhaseValue = Attack; + _currentPhase = ADSRPhase.Attack; + } + } + + public override void OnAttach() + { + base.OnAttach(); + + _currentPhase = ADSRPhase.Attack; + _currentPhaseValue = Attack; + _repetitionCount = 0; + EffectBrush.Opacity = 0f; + } + + #endregion + + // ReSharper disable once InconsistentNaming + private enum ADSRPhase + { + Attack, + Decay, + Sustain, + Release, + Pause, + } + } +}