diff --git a/Plazma.sln b/Plazma.sln index 669e744..2daff0c 100644 --- a/Plazma.sln +++ b/Plazma.sln @@ -51,38 +51,38 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerfShared", "Performance\P EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Debug|x64 = Debug|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7858F8F1-497A-4261-94D7-339442B09494}.Debug|Any CPU.ActiveCfg = Debug|x64 - {7858F8F1-497A-4261-94D7-339442B09494}.Debug|Any CPU.Build.0 = Debug|x64 - {7858F8F1-497A-4261-94D7-339442B09494}.Release|Any CPU.ActiveCfg = Release|x64 - {7858F8F1-497A-4261-94D7-339442B09494}.Release|Any CPU.Build.0 = Release|x64 - {AF6A9738-F676-408A-B1B9-E7F43631BC08}.Debug|Any CPU.ActiveCfg = Debug|x64 - {AF6A9738-F676-408A-B1B9-E7F43631BC08}.Debug|Any CPU.Build.0 = Debug|x64 - {AF6A9738-F676-408A-B1B9-E7F43631BC08}.Release|Any CPU.ActiveCfg = Release|x64 - {AF6A9738-F676-408A-B1B9-E7F43631BC08}.Release|Any CPU.Build.0 = Release|x64 - {D2B0088E-5452-48FE-B804-FA985A114635}.Debug|Any CPU.ActiveCfg = Debug|x64 - {D2B0088E-5452-48FE-B804-FA985A114635}.Debug|Any CPU.Build.0 = Debug|x64 - {D2B0088E-5452-48FE-B804-FA985A114635}.Release|Any CPU.ActiveCfg = Release|x64 - {D2B0088E-5452-48FE-B804-FA985A114635}.Release|Any CPU.Build.0 = Release|x64 - {E2532556-570E-4416-B163-00CA1EAAE03C}.Debug|Any CPU.ActiveCfg = Debug|x64 - {E2532556-570E-4416-B163-00CA1EAAE03C}.Debug|Any CPU.Build.0 = Debug|x64 - {E2532556-570E-4416-B163-00CA1EAAE03C}.Release|Any CPU.ActiveCfg = Release|x64 - {E2532556-570E-4416-B163-00CA1EAAE03C}.Release|Any CPU.Build.0 = Release|x64 - {32D301FD-1E4D-431C-8C9D-E304E769C19F}.Debug|Any CPU.ActiveCfg = Debug|x64 - {32D301FD-1E4D-431C-8C9D-E304E769C19F}.Debug|Any CPU.Build.0 = Debug|x64 - {32D301FD-1E4D-431C-8C9D-E304E769C19F}.Release|Any CPU.ActiveCfg = Release|x64 - {32D301FD-1E4D-431C-8C9D-E304E769C19F}.Release|Any CPU.Build.0 = Release|x64 - {960AD89D-364C-4455-8C7A-3B2D4188A0A1}.Debug|Any CPU.ActiveCfg = Debug|x64 - {960AD89D-364C-4455-8C7A-3B2D4188A0A1}.Debug|Any CPU.Build.0 = Debug|x64 - {960AD89D-364C-4455-8C7A-3B2D4188A0A1}.Release|Any CPU.ActiveCfg = Release|x64 - {960AD89D-364C-4455-8C7A-3B2D4188A0A1}.Release|Any CPU.Build.0 = Release|x64 - {A5790981-C319-48BD-9790-34F2C2E775B4}.Debug|Any CPU.ActiveCfg = Debug|x64 - {A5790981-C319-48BD-9790-34F2C2E775B4}.Debug|Any CPU.Build.0 = Debug|x64 - {A5790981-C319-48BD-9790-34F2C2E775B4}.Release|Any CPU.ActiveCfg = Release|x64 - {A5790981-C319-48BD-9790-34F2C2E775B4}.Release|Any CPU.Build.0 = Release|x64 + {32D301FD-1E4D-431C-8C9D-E304E769C19F}.Release|x64.ActiveCfg = Release|x64 + {32D301FD-1E4D-431C-8C9D-E304E769C19F}.Release|x64.Build.0 = Release|x64 + {32D301FD-1E4D-431C-8C9D-E304E769C19F}.Debug|x64.ActiveCfg = Debug|x64 + {32D301FD-1E4D-431C-8C9D-E304E769C19F}.Debug|x64.Build.0 = Debug|x64 + {960AD89D-364C-4455-8C7A-3B2D4188A0A1}.Release|x64.ActiveCfg = Release|x64 + {960AD89D-364C-4455-8C7A-3B2D4188A0A1}.Release|x64.Build.0 = Release|x64 + {960AD89D-364C-4455-8C7A-3B2D4188A0A1}.Debug|x64.ActiveCfg = Debug|x64 + {960AD89D-364C-4455-8C7A-3B2D4188A0A1}.Debug|x64.Build.0 = Debug|x64 + {A5790981-C319-48BD-9790-34F2C2E775B4}.Release|x64.ActiveCfg = Release|x64 + {A5790981-C319-48BD-9790-34F2C2E775B4}.Release|x64.Build.0 = Release|x64 + {A5790981-C319-48BD-9790-34F2C2E775B4}.Debug|x64.ActiveCfg = Debug|x64 + {A5790981-C319-48BD-9790-34F2C2E775B4}.Debug|x64.Build.0 = Debug|x64 + {7858F8F1-497A-4261-94D7-339442B09494}.Release|x64.ActiveCfg = Release|x64 + {7858F8F1-497A-4261-94D7-339442B09494}.Release|x64.Build.0 = Release|x64 + {7858F8F1-497A-4261-94D7-339442B09494}.Debug|x64.ActiveCfg = Debug|x64 + {7858F8F1-497A-4261-94D7-339442B09494}.Debug|x64.Build.0 = Debug|x64 + {D2B0088E-5452-48FE-B804-FA985A114635}.Release|x64.ActiveCfg = Release|x64 + {D2B0088E-5452-48FE-B804-FA985A114635}.Release|x64.Build.0 = Release|x64 + {D2B0088E-5452-48FE-B804-FA985A114635}.Debug|x64.ActiveCfg = Debug|x64 + {D2B0088E-5452-48FE-B804-FA985A114635}.Debug|x64.Build.0 = Debug|x64 + {AF6A9738-F676-408A-B1B9-E7F43631BC08}.Release|x64.ActiveCfg = Release|x64 + {AF6A9738-F676-408A-B1B9-E7F43631BC08}.Release|x64.Build.0 = Release|x64 + {AF6A9738-F676-408A-B1B9-E7F43631BC08}.Debug|x64.ActiveCfg = Debug|x64 + {AF6A9738-F676-408A-B1B9-E7F43631BC08}.Debug|x64.Build.0 = Debug|x64 + {E2532556-570E-4416-B163-00CA1EAAE03C}.Release|x64.ActiveCfg = Release|x64 + {E2532556-570E-4416-B163-00CA1EAAE03C}.Release|x64.Build.0 = Release|x64 + {E2532556-570E-4416-B163-00CA1EAAE03C}.Debug|x64.ActiveCfg = Debug|x64 + {E2532556-570E-4416-B163-00CA1EAAE03C}.Debug|x64.Build.0 = Debug|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Plazma/Behaviors/EasingRandomBehavior.cs b/Plazma/Behaviors/EasingRandomBehavior.cs index c9d9248..240640e 100644 --- a/Plazma/Behaviors/EasingRandomBehavior.cs +++ b/Plazma/Behaviors/EasingRandomBehavior.cs @@ -57,21 +57,38 @@ public override void Update(TimeSpan timeElapsed) _ => Value }; + // Override the current value between the start and end if the update delegate is set if (this.settings.UpdateValue is not null) { Value = this.settings.UpdateValue.Invoke(Value); } + // Override the random start min value if the update delegate is set if (this.settings.UpdateRandomStartMin is not null) { this.settings = this.settings with { RandomStartMin = this.settings.UpdateRandomStartMin?.Invoke(Value) ?? 0f }; } + // Override the random start max value if the update delegate is set if (this.settings.UpdateRandomStartMax is not null) { this.settings = this.settings with { RandomStartMax = this.settings.UpdateRandomStartMax?.Invoke(Value) ?? 0f }; } + // Override the random change min value if the update delegate is set + // This is the end value that the easing function is trying to approach + if (this.settings.UpdateRandomChangeMin is not null) + { + this.settings = this.settings with { RandomChangeMin = this.settings.UpdateRandomChangeMin?.Invoke(Value) ?? 0f }; + } + + // Override the random change max value if the update delegate is set + // This is the end value that the easing function is trying to approach + if (this.settings.UpdateRandomChangeMax is not null) + { + this.settings = this.settings with { RandomChangeMax = this.settings.UpdateRandomChangeMax?.Invoke(Value) ?? 0f }; + } + base.Update(timeElapsed); } diff --git a/Plazma/Behaviors/EasingRandomBehaviorSettings.cs b/Plazma/Behaviors/EasingRandomBehaviorSettings.cs index fedb703..90d37cb 100644 --- a/Plazma/Behaviors/EasingRandomBehaviorSettings.cs +++ b/Plazma/Behaviors/EasingRandomBehaviorSettings.cs @@ -39,7 +39,7 @@ public readonly record struct EasingRandomBehaviorSettings public float RandomStartMax { get; init; } /// - /// Gets a delegate that will give the current value and return a value. + /// Gets a delegate that will override or manipulate the current value. /// /// /// @@ -53,8 +53,7 @@ public readonly record struct EasingRandomBehaviorSettings public Func? UpdateValue { get; init; } /// - /// Gets a delegate that will give the current value of the behavior and - /// returns a value that will be used as the new . + /// Gets a delegate that will override or manipulate the current value. /// /// /// @@ -68,8 +67,7 @@ public readonly record struct EasingRandomBehaviorSettings public Func? UpdateRandomStartMin { get; init; } /// - /// Gets a delegate that will give the current value of the behavior and - /// returns a value that will be used as the new . + /// Gets a delegate that will override or manipulate the current value. /// /// /// @@ -82,6 +80,34 @@ public readonly record struct EasingRandomBehaviorSettings [JsonIgnore] public Func? UpdateRandomStartMax { get; init; } + /// + /// Gets a delegate that will override or manipulate the current value. + /// + /// + /// + /// This is invoked during the behavior update process. + /// + /// + /// The value returned from the delegate will be used as the new value for the . + /// + /// + [JsonIgnore] + public Func? UpdateRandomChangeMin { get; init; } + + /// + /// Gets a delegate that will override or manipulate the current value. + /// + /// + /// + /// This is invoked during the behavior update process. + /// + /// + /// The value returned from the delegate will be used as the new value for the . + /// + /// + [JsonIgnore] + public Func? UpdateRandomChangeMax { get; init; } + /// /// Gets the minimum amount of change used in randomization. /// diff --git a/Testing/PlazmaTesting/CustomControls/MinMax.cs b/Testing/PlazmaTesting/CustomControls/MinMax.cs new file mode 100644 index 0000000..a88d994 --- /dev/null +++ b/Testing/PlazmaTesting/CustomControls/MinMax.cs @@ -0,0 +1,202 @@ +// +// Copyright (c) KinsonDigital. All rights reserved. +// + +namespace PlazmaTesting.CustomControls; + +using System.Drawing; +using KdGui; +using KdGui.Factories; + +public class MinMax +{ + private readonly IControlGroup group; + private readonly ICheckBox randomize; + private readonly ISlider value; + private readonly ISlider randomMin; + private readonly ISlider randomMax; + private readonly ICheckBox lockRanges; + private readonly ICheckBox growShrink; + + public MinMax(string title, string minText = "Min", string maxText = "Max") + { + var ctrlFactory = new ControlFactory(); + + this.randomMin = ctrlFactory.CreateSlider(); + this.randomMin.Text = minText; + this.randomMin.Min = 0; + this.randomMin.Max = 100; + this.randomMin.Value = 50; + this.randomMin.ValueChanged += RandomMin_OnValueChanged; + this.randomMin.Visible = false; + + this.randomMax = ctrlFactory.CreateSlider(); + this.randomMax.Text = maxText; + this.randomMax.Min = 0; + this.randomMax.Max = 100; + this.randomMax.Value = 50; + this.randomMax.ValueChanged += RandomMax_OnValueChanged; + this.randomMax.Visible = false; + + this.randomize = ctrlFactory.CreateCheckbox(); + this.randomize.IsChecked = false; + this.randomize.LabelWhenChecked = "Randomized"; + this.randomize.LabelWhenUnchecked = "Not Randomized"; + this.randomize.CheckedChanged += Randomize_OnCheckedChanged; + + this.growShrink = ctrlFactory.CreateCheckbox(); + this.growShrink.IsChecked = true; + this.growShrink.Visible = true; + this.growShrink.LabelWhenChecked = "Growing"; + this.growShrink.LabelWhenUnchecked = "Shrinking"; + + this.value = ctrlFactory.CreateSlider(); + this.value.Text = "Value"; + this.value.Visible = true; + this.value.Min = 0; + this.value.Max = 100; + this.value.Value = 100; + + this.lockRanges = ctrlFactory.CreateCheckbox(); + this.lockRanges.IsChecked = true; + this.lockRanges.Visible = false; + this.lockRanges.LabelWhenChecked = "Locked"; + this.lockRanges.LabelWhenUnchecked = "Unlocked"; + this.lockRanges.CheckedChanged += LockRanges_OnCheckedChanged; + + this.group = ctrlFactory.CreateControlGroup(); + this.group.AutoSizeToFitContent = true; + this.group.Title = title; + this.group.Add(this.randomize); + this.group.Add(this.lockRanges); + this.group.Add(this.randomMin); + this.group.Add(this.randomMax); + this.group.Add(this.growShrink); + this.group.Add(this.value); + this.group.Render(); + } + + public string MinText + { + get => this.randomMin.Text; + set => this.randomMin.Text = value; + } + + public string MaxText + { + get => this.randomMax.Text; + set => this.randomMax.Text = value; + } + + public float Min + { + get => this.randomMin.Value; + set + { + this.randomMin.Min = value; + this.randomMax.Min = value; + } + } + + public float Max + { + get => this.randomMax.Value; + set + { + this.randomMin.Max = value; + this.randomMax.Max = value; + } + } + + public float MinValue + { + get => this.randomMin.Value; + set => this.randomMin.Value = value; + } + + public float MaxValue + { + get => this.randomMax.Value; + set => this.randomMax.Value = value; + } + + public Point Position + { + get => this.group.Position; + set => this.group.Position = value; + } + + public float Value + { + get => this.value.Value; + set => this.value.Value = value; + } + + public bool GrowValue => this.growShrink.IsChecked; + + public bool IsRandomized => this.randomize.IsChecked; + + public bool IsNotRandomized => !this.randomize.IsChecked; + + public float Left => this.group.Left; + + public float Top => this.group.Top; + + public float Right => this.group.Right; + + public float Bottom => this.group.Bottom; + + public float Width => this.group.Width; + + public float Height => this.group.Height; + + public void Render() => this.group.Render(); + + private void Randomize_OnCheckedChanged(object? sender, bool e) + { + this.growShrink.Visible = !this.growShrink.Visible; + this.value.Visible = !this.value.Visible; + this.randomMin.Visible = !this.randomMin.Visible; + this.randomMax.Visible = !this.randomMax.Visible; + this.lockRanges.Visible = !this.lockRanges.Visible; + } + + private void RandomMin_OnValueChanged(object? sender, float e) + { + if (this.lockRanges.IsChecked) + { + this.randomMax.Value = e; + } + } + + private void RandomMax_OnValueChanged(object? sender, float e) + { + if (this.lockRanges.IsChecked) + { + this.randomMin.Value = e; + } + } + + private void LockRanges_OnCheckedChanged(object? sender, bool e) + { + if (!e) + { + return; + } + + if (Math.Abs(this.randomMin.Value - this.randomMax.Value) < 0.0001) + { + return; + } + + var minValue = Math.Min(this.randomMin.Value, this.randomMax.Value); + var maxValue = Math.Max(this.randomMax.Value, this.randomMax.Value); + var delta = maxValue - minValue; + + var newMinValue = minValue + (delta / 2f); + var newMaxValue = maxValue - (delta / 2f); + + this.randomMin.Value = newMinValue; + this.randomMax.Value = newMaxValue; + } +} diff --git a/Testing/PlazmaTesting/PlazmaTesting.csproj b/Testing/PlazmaTesting/PlazmaTesting.csproj index 056df4d..dd8c0e2 100644 --- a/Testing/PlazmaTesting/PlazmaTesting.csproj +++ b/Testing/PlazmaTesting/PlazmaTesting.csproj @@ -10,7 +10,7 @@ - + all @@ -34,6 +34,9 @@ Always + + Always + diff --git a/Testing/PlazmaTesting/Scenes/AllAttributesScene.cs b/Testing/PlazmaTesting/Scenes/AllAttributesScene.cs new file mode 100644 index 0000000..8cf0cde --- /dev/null +++ b/Testing/PlazmaTesting/Scenes/AllAttributesScene.cs @@ -0,0 +1,437 @@ +// +// Copyright (c) KinsonDigital. All rights reserved. +// + +namespace PlazmaTesting.Scenes; + +using System.Drawing; +using System.Numerics; +using CustomControls; +using Plazma; +using Plazma.Behaviors; +using Plazma.Factories; +using Velaptor; +using Velaptor.Content; +using Velaptor.Factories; +using Velaptor.Graphics; +using Velaptor.Graphics.Renderers; +using Velaptor.Scene; + +public class AllAttributesScene : SceneBase +{ + private const int Spacing = 15; + private readonly ITextureRenderer textureRenderer; + private readonly ITextureLoader textureLoader = new ParticleTextureLoader(); + private ParticleEngine? engine; + private MinMax? alphaStartMinMax; + private MinMax? redStartMinMax; + private MinMax? greenStartMinMax; + private MinMax? blueStartMinMax; + private MinMax? alphaEndMinMax; + private MinMax? redEndMinMax; + private MinMax? greenEndMinMax; + private MinMax? blueEndMinMax; + private MinMax? angleStartMinMax; + private MinMax? angleEndMinMax; + + /// + /// Initializes a new instance of the class. + /// + public AllAttributesScene() => this.textureRenderer = RendererFactory.CreateTextureRenderer(); + + /// + /// Initializes a new instance of the class. + /// + /// + /// Loads the content. + /// + public override void LoadContent() + { + if (IsLoaded) + { + return; + } + + var allSettings = CreateSettings(); + + var effect = new ParticleEffect("drop", allSettings) + { + SpawnRateMin = 125, + SpawnRateMax = 125, + TotalParticles = 50, + SpawnLocation = new Vector2(WindowSize.Width / 2f, WindowSize.Height / 2f), + }; + + var poolFactory = new ParticlePoolFactory(); + this.engine = new ParticleEngine(); + this.engine.AddPool(poolFactory.Create(effect, this.textureLoader)); + + this.engine.ParticlePools[0].Effect = this.engine.ParticlePools[0].Effect with + { + SpawnLocation = new Vector2(WindowSize.Width / 2f, WindowSize.Height / 2f) + }; + this.engine.LoadTextures(); + + CreateUi(); + + base.LoadContent(); + } + + /// + /// Unloads the content. + /// + public override void UnloadContent() + { + if (!IsLoaded) + { + return; + } + + this.engine?.Dispose(); + this.textureLoader.Dispose(); + + base.UnloadContent(); + } + + /// + /// Updates the scene. + /// + /// The time passed for the current frame. + public override void Update(FrameTime frameTime) + { + this.engine.Update(frameTime.ElapsedTime); + + PositionUi(); + + base.Update(frameTime); + } + + /// + /// Renders the scene. + /// + public override void Render() + { + foreach (var pool in this.engine.ParticlePools) + { + foreach (var particle in pool.Particles) + { + if (!particle.IsAlive) + { + continue; + } + + var renderPos = particle.Position; + var renderPosX = renderPos.X; + var renderPosY = renderPos.Y; + + var srcRect = new Rectangle(0, 0, (int)pool.PoolTexture.Width, (int)pool.PoolTexture.Height); + var destRect = new Rectangle((int)renderPosX, (int)renderPosY, (int)pool.PoolTexture.Width, (int)pool.PoolTexture.Height); + + this.textureRenderer.Render(pool.PoolTexture, srcRect, destRect, 1f, -particle.Angle, particle.TintColor, RenderEffects.None); + } + } + + this.alphaStartMinMax.Render(); + this.alphaEndMinMax.Render(); + + this.redStartMinMax.Render(); + this.redEndMinMax.Render(); + + this.greenStartMinMax.Render(); + this.greenEndMinMax.Render(); + + this.blueStartMinMax.Render(); + this.blueEndMinMax.Render(); + + this.angleStartMinMax.Render(); + this.angleEndMinMax.Render(); + + base.Render(); + } + + private void CreateUi() + { + CreateColorUi(); + + this.angleStartMinMax = new MinMax("Angle Start"); + this.angleStartMinMax.Min = 0; + this.angleStartMinMax.Max = 360; + this.angleStartMinMax.Value = 0; + + this.angleEndMinMax = new MinMax("Angle End"); + this.angleEndMinMax.Min = 0; + this.angleEndMinMax.Max = 360; + + Render(); + } + + private void CreateColorUi() + { + this.alphaStartMinMax = new MinMax("Alpha Start"); + this.alphaStartMinMax.Min = 0; + this.alphaStartMinMax.Max = 255; + this.alphaStartMinMax.MinValue = 255; + this.alphaStartMinMax.MaxValue = 255; + this.alphaStartMinMax.Value = 255; + + this.alphaEndMinMax = new MinMax("Alpha End"); + this.alphaEndMinMax.Min = 0; + this.alphaEndMinMax.Max = 255; + this.alphaEndMinMax.MinValue = 255; + this.alphaEndMinMax.MaxValue = 255; + + this.redStartMinMax = new MinMax("Red Start"); + this.redStartMinMax.Min = 0; + this.redStartMinMax.Max = 255; + this.redStartMinMax.MinValue = 255; + this.redStartMinMax.MaxValue = 255; + this.redStartMinMax.Value = 255; + + this.redEndMinMax = new MinMax("Red End"); + this.redEndMinMax.Min = 0; + this.redEndMinMax.Max = 255; + this.redEndMinMax.MinValue = 0; + this.redEndMinMax.MaxValue = 0; + this.redEndMinMax.Value = 0; + + this.greenStartMinMax = new MinMax("Green Start"); + this.greenStartMinMax.Min = 0; + this.greenStartMinMax.Max = 255; + this.greenStartMinMax.MinValue = 0; + this.greenStartMinMax.MaxValue = 0; + this.greenStartMinMax.Value = 255; + + this.greenEndMinMax = new MinMax("Green End"); + this.greenEndMinMax.Min = 0; + this.greenEndMinMax.Max = 255; + this.greenEndMinMax.MinValue = 0; + this.greenEndMinMax.MaxValue = 0; + this.greenEndMinMax.Value = 0; + + this.blueStartMinMax = new MinMax("Blue Start"); + this.blueStartMinMax.Min = 0; + this.blueStartMinMax.Max = 255; + this.blueStartMinMax.MinValue = 0; + this.blueStartMinMax.MaxValue = 0; + this.blueStartMinMax.Value = 255; + + this.blueEndMinMax = new MinMax("Blue End"); + this.blueEndMinMax.Min = 0; + this.blueEndMinMax.Max = 255; + this.blueEndMinMax.MinValue = 255; + this.blueEndMinMax.MaxValue = 255; + this.blueEndMinMax.Value = 255; + } + + private void PositionUi() + { + // Color Starts + this.alphaStartMinMax.Position = new Point(Spacing, Spacing); + this.redStartMinMax.Position = new Point(Spacing, (int)this.alphaStartMinMax.Bottom + Spacing); + this.greenStartMinMax.Position = new Point(Spacing, (int)this.redStartMinMax.Bottom + Spacing); + this.blueStartMinMax.Position = new Point(Spacing, (int)this.greenStartMinMax.Bottom + Spacing); + + // Color Ends + this.alphaEndMinMax.Position = new Point((int)this.alphaStartMinMax.Right + Spacing, (int)this.alphaStartMinMax.Top); + this.redEndMinMax.Position = new Point((int)this.redStartMinMax.Right + Spacing, (int)this.alphaEndMinMax.Bottom + Spacing); + this.greenEndMinMax.Position = new Point((int)this.greenStartMinMax.Right + Spacing, (int)this.redEndMinMax.Bottom + Spacing); + this.blueEndMinMax.Position = new Point((int)this.blueStartMinMax.Right + Spacing, (int)this.greenEndMinMax.Bottom + Spacing); + + // Angle + this.angleStartMinMax.Position = new Point((int)WindowSize.Width - ((int)this.angleStartMinMax.Width + Spacing), Spacing); + this.angleEndMinMax.Position = new Point((int)WindowSize.Width - ((int)this.angleEndMinMax.Width + Spacing), (int)this.angleStartMinMax.Bottom + Spacing); + } + + private EasingRandomBehaviorSettings[] CreateSettings() + { + var alphaSettings = new EasingRandomBehaviorSettings + { + ApplyToAttribute = BehaviorAttribute.AlphaColorComponent, + RandomStartMin = 255, + RandomStartMax = 255, + RandomChangeMin = 255, + RandomChangeMax = 255, + LifeTimeMillisecondsMin = 2000, + LifeTimeMillisecondsMax = 2000, + UpdateRandomStartMin = (_) => this.alphaStartMinMax.IsRandomized + ? this.alphaStartMinMax.MinValue + : this.alphaStartMinMax.Value, + UpdateRandomStartMax = (_) => this.alphaStartMinMax.IsRandomized + ? this.alphaStartMinMax.MaxValue + : this.alphaStartMinMax.Value, + UpdateRandomChangeMin = (_) => this.alphaEndMinMax.IsRandomized + ? this.alphaEndMinMax.MinValue - this.alphaStartMinMax.MinValue + : this.alphaEndMinMax.Value - this.alphaStartMinMax.Value, + UpdateRandomChangeMax = (_) => this.alphaEndMinMax.IsRandomized + ? this.alphaEndMinMax.MaxValue - this.alphaStartMinMax.MaxValue + : this.alphaEndMinMax.Value - this.alphaStartMinMax.Value, + EasingFunctionType = EasingFunction.EaseIn, + }; + + var redSettings = new EasingRandomBehaviorSettings + { + ApplyToAttribute = BehaviorAttribute.RedColorComponent, + RandomStartMin = 255, + RandomStartMax = 255, + RandomChangeMin = -255, + RandomChangeMax = -255, + LifeTimeMillisecondsMin = 2000, + LifeTimeMillisecondsMax = 2000, + // UpdateValue = (value) => this.redEndMinMax.IsRandomized ? value : this.redEndMinMax.Value, + UpdateRandomStartMin = (_) => this.redStartMinMax.IsRandomized + ? this.redStartMinMax.MinValue + : this.redStartMinMax.Value, + UpdateRandomStartMax = (_) => this.redStartMinMax.IsRandomized + ? this.redStartMinMax.MaxValue + : this.redStartMinMax.Value, + UpdateRandomChangeMin = (_) => this.redEndMinMax.IsRandomized + ? this.redEndMinMax.MinValue - this.redStartMinMax.MinValue + : this.redEndMinMax.Value - this.redStartMinMax.Value, + UpdateRandomChangeMax = (_) => this.redEndMinMax.IsRandomized + ? this.redEndMinMax.MaxValue - this.redStartMinMax.MaxValue + : this.redEndMinMax.Value - this.redStartMinMax.Value, + EasingFunctionType = EasingFunction.EaseIn, + }; + + var greenSettings = new EasingRandomBehaviorSettings + { + ApplyToAttribute = BehaviorAttribute.GreenColorComponent, + RandomStartMin = 255, + RandomStartMax = 255, + RandomChangeMin = -255, + RandomChangeMax = -255, + LifeTimeMillisecondsMin = 2000, + LifeTimeMillisecondsMax = 2000, + // UpdateValue = (value) => this.greenEndMinMax.IsRandomized ? value : this.greenEndMinMax.Value, + UpdateRandomStartMin = (_) => this.greenStartMinMax.IsRandomized + ? this.greenStartMinMax.MinValue + : this.greenStartMinMax.Value, + UpdateRandomStartMax = (_) => this.greenStartMinMax.IsRandomized + ? this.greenStartMinMax.MaxValue + : this.greenStartMinMax.Value, + UpdateRandomChangeMin = (_) => this.greenEndMinMax.IsRandomized + ? this.greenEndMinMax.MinValue - this.greenStartMinMax.MinValue + : this.greenEndMinMax.Value - this.greenStartMinMax.Value, + UpdateRandomChangeMax = (_) => this.greenEndMinMax.IsRandomized + ? this.greenEndMinMax.MaxValue - this.greenStartMinMax.MaxValue + : this.greenEndMinMax.Value - this.greenStartMinMax.Value, + EasingFunctionType = EasingFunction.EaseIn, + }; + + var blueSettings = new EasingRandomBehaviorSettings + { + ApplyToAttribute = BehaviorAttribute.BlueColorComponent, + RandomStartMin = 255, + RandomStartMax = 255, + RandomChangeMin = 255, + RandomChangeMax = 255, + LifeTimeMillisecondsMin = 2000, + LifeTimeMillisecondsMax = 2000, + // UpdateValue = (value) => this.blueEndMinMax.IsRandomized ? value : this.blueEndMinMax.Value, + UpdateRandomStartMin = (_) => this.blueStartMinMax.IsRandomized + ? this.blueStartMinMax.MinValue + : this.blueStartMinMax.Value, + UpdateRandomStartMax = (_) => this.blueStartMinMax.IsRandomized + ? this.blueStartMinMax.MaxValue + : this.blueStartMinMax.Value, + UpdateRandomChangeMin = (_) => this.blueEndMinMax.IsRandomized + ? this.blueEndMinMax.MinValue - this.blueStartMinMax.MinValue + : this.blueEndMinMax.Value - this.blueStartMinMax.Value, + UpdateRandomChangeMax = (_) => this.blueEndMinMax.IsRandomized + ? this.blueEndMinMax.MaxValue - this.blueStartMinMax.MaxValue + : this.blueEndMinMax.Value - this.blueStartMinMax.Value, + EasingFunctionType = EasingFunction.EaseIn, + }; + + var angleSettings = new EasingRandomBehaviorSettings + { + ApplyToAttribute = BehaviorAttribute.Angle, + RandomStartMin = 0, + RandomStartMax = 0, + RandomChangeMin = 0, + RandomChangeMax = 0, + LifeTimeMillisecondsMin = 1000, + LifeTimeMillisecondsMax = 1000, + UpdateRandomStartMin = (_) => this.angleStartMinMax.IsRandomized + ? this.angleStartMinMax.MinValue + : this.angleStartMinMax.Value, + UpdateRandomStartMax = (_) => this.angleStartMinMax.IsRandomized + ? this.angleStartMinMax.MaxValue + : this.angleStartMinMax.Value, + UpdateRandomChangeMin = (_) => + { + if (this.angleEndMinMax.IsRandomized) + { + return this.angleEndMinMax.Value - this.angleStartMinMax.Value; + } + + return this.angleEndMinMax.GrowValue + ? this.angleEndMinMax.Value - this.angleStartMinMax.Value + : this.angleStartMinMax.Value - this.angleEndMinMax.Value; + }, + UpdateRandomChangeMax = (_) => + { + if (this.angleEndMinMax.IsRandomized) + { + return this.angleEndMinMax.Value - this.angleStartMinMax.Value; + } + + return this.angleEndMinMax.IsRandomized + ? this.angleEndMinMax.Value - this.angleStartMinMax.Value + : this.angleStartMinMax.Value - this.angleEndMinMax.Value; + }, + EasingFunctionType = EasingFunction.EaseIn, + }; + + var sizeSettings = new EasingRandomBehaviorSettings + { + ApplyToAttribute = BehaviorAttribute.Size, + RandomStartMin = 1, + RandomStartMax = 1, + RandomChangeMin = 1, + RandomChangeMax = 1, + LifeTimeMillisecondsMin = 2000, + LifeTimeMillisecondsMax = 2000, + EasingFunctionType = EasingFunction.EaseIn, + }; + + var winCenterX = WindowSize.Width / 2f; + var winCenterY = WindowSize.Height / 2f; + + var xSettings = new EasingRandomBehaviorSettings + { + ApplyToAttribute = BehaviorAttribute.X, + RandomStartMin = winCenterX, + RandomStartMax = winCenterX, + RandomChangeMin = winCenterX, + RandomChangeMax = winCenterX, + LifeTimeMillisecondsMin = 2000, + LifeTimeMillisecondsMax = 2000, + EasingFunctionType = EasingFunction.EaseIn, + }; + + var yPosSettings = new EasingRandomBehaviorSettings + { + ApplyToAttribute = BehaviorAttribute.Y, + RandomStartMin = winCenterY, + RandomStartMax = winCenterY, + RandomChangeMin = winCenterY, + RandomChangeMax = winCenterY, + LifeTimeMillisecondsMin = 2000, + LifeTimeMillisecondsMax = 2000, + EasingFunctionType = EasingFunction.EaseIn, + }; + + return + [ + alphaSettings, + redSettings, + greenSettings, + blueSettings, + angleSettings, + sizeSettings, + xSettings, + yPosSettings, + ]; + } +}