348 lines
14 KiB
C#
348 lines
14 KiB
C#
// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
|
|
// This code can only be used under the standard Unity Asset Store End User License Agreement
|
|
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using Doozy.Editor.Common.Extensions;
|
|
using Doozy.Editor.EditorUI;
|
|
using Doozy.Editor.EditorUI.Components;
|
|
using Doozy.Editor.EditorUI.Components.Internal;
|
|
using Doozy.Editor.UIElements;
|
|
using Doozy.Runtime.Reactor;
|
|
using Doozy.Runtime.Reactor.Easings;
|
|
using Doozy.Runtime.UIElements.Extensions;
|
|
using UnityEditor;
|
|
using UnityEditor.UIElements;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using PlayMode = Doozy.Runtime.Reactor.PlayMode;
|
|
|
|
namespace Doozy.Editor.Reactor.Drawers
|
|
{
|
|
[CustomPropertyDrawer(typeof(ReactionSettings), true)]
|
|
public class ReactionSettingsDrawer : PropertyDrawer
|
|
{
|
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {}
|
|
|
|
public override VisualElement CreatePropertyGUI(SerializedProperty property)
|
|
{
|
|
var target = property.GetTargetObjectOfProperty() as ReactionSettings;
|
|
|
|
var drawer = new VisualElement();
|
|
|
|
var startDelayField = newStartDelayField;
|
|
var durationField = newDurationField;
|
|
var loopsField = newLoopsField;
|
|
var loopDelayField = newLoopDelayField;
|
|
|
|
var playModeEnum = new EnumField().SetBindingPath("PlayMode").ResetLayout();
|
|
var playModeField = FluidField.Get("Play Mode", playModeEnum).SetStyleFlexGrow(0).SetStyleMinWidth(160);
|
|
|
|
var easeModeEnum = new EnumField().SetBindingPath("EaseMode").ResetLayout().SetTooltip("Animation ease mode can be either an Ease or an AnimationCurve");
|
|
var easeModeField = FluidField.Get("Ease Mode", easeModeEnum).SetStyleFlexGrow(0).SetStyleMinWidth(128);
|
|
|
|
var easeEnum = new EnumField().SetBindingPath("Ease").ResetLayout().SetTooltip("Ease for the animation");
|
|
var easeField = FluidField.Get("Ease", easeEnum);
|
|
|
|
var animationCurve = new CurveField().SetBindingPath("Curve").ResetLayout().SetTooltip("AnimationCurve for the animation");
|
|
var animationCurveField = FluidField.Get("Animation Curve", animationCurve);
|
|
|
|
var strength = new FloatField().SetBindingPath("Strength").ResetLayout().SetTooltip("Multiplier applied to the current value for spring and shake play modes");
|
|
var strengthField = FluidField.Get("Strength", strength);
|
|
|
|
var vibration = new IntegerField().SetBindingPath("Vibration").ResetLayout().SetTooltip("Minimum number of oscillations for spring and shake play modes.\nHigher value means more oscillations during the reaction's duration");
|
|
var vibrationField = FluidField.Get("Vibration", vibration);
|
|
|
|
var elasticity = new FloatField().SetBindingPath("Elasticity").ResetLayout().SetTooltip("Spring elasticity controls how much the current value goes back beyond the start value when contracting.\n0 - current value does not go beyond the start value\n1 - current value goes beyond the start value at maximum elastic force");
|
|
var elasticityField = FluidField.Get("Elasticity", elasticity);
|
|
|
|
var fadeOutShake = FluidToggleSwitch.Get(EditorSelectableColors.Reactor.Red).SetBindingPath("FadeOutShake").SetLabelText("Fade Out Shake").SetTooltip("Fade out the shake animation, by easing the last 20% of cycles (shakes) into a semi-smooth transition");
|
|
|
|
{
|
|
VisualElement row = new VisualElement().SetStyleFlexDirection(FlexDirection.Row);
|
|
drawer.Add(row);
|
|
row.Add(startDelayField);
|
|
row.AddSpace(4, 0);
|
|
row.Add(durationField);
|
|
row.AddSpace(4, 0);
|
|
row.Add(loopsField);
|
|
row.AddSpace(4, 0);
|
|
row.Add(loopDelayField);
|
|
}
|
|
drawer.AddSpace(0, 4);
|
|
{
|
|
VisualElement row = new VisualElement().SetStyleFlexDirection(FlexDirection.Row);
|
|
drawer.Add(row);
|
|
|
|
row.Add(playModeField);
|
|
row.AddSpace(4, 0);
|
|
row.Add(easeModeField);
|
|
row.AddSpace(4, 0);
|
|
row.Add(easeField);
|
|
row.Add(animationCurveField);
|
|
}
|
|
|
|
VisualElement extraRow = new VisualElement().SetStyleFlexDirection(FlexDirection.Row).SetStyleMargins(0, 4, 0, 4);
|
|
{
|
|
extraRow.Add(strengthField);
|
|
extraRow.AddSpace(4, 0);
|
|
extraRow.Add(vibrationField);
|
|
extraRow.AddSpace(4, 0);
|
|
extraRow.Add(elasticityField);
|
|
extraRow.AddSpace(4, 0);
|
|
extraRow.Add(fadeOutShake);
|
|
}
|
|
drawer.Add(extraRow);
|
|
|
|
#region PlayMode
|
|
|
|
var invisibleLoopsField = new IntegerField { bindingPath = "Loops" }.SetStyleDisplay(DisplayStyle.None);
|
|
invisibleLoopsField.RegisterValueChangedCallback(evt => UpdatePlayMode((PlayMode)playModeEnum.value));
|
|
drawer.AddChild(invisibleLoopsField);
|
|
|
|
var invisibleUseRandomLoopsField = new Toggle { bindingPath = "UseRandomLoops" }.SetStyleDisplay(DisplayStyle.None);
|
|
invisibleUseRandomLoopsField.RegisterValueChangedCallback(evt => UpdatePlayMode((PlayMode)playModeEnum.value));
|
|
drawer.AddChild(invisibleUseRandomLoopsField);
|
|
|
|
playModeEnum.RegisterValueChangedCallback(evt =>
|
|
{
|
|
try
|
|
{
|
|
UpdatePlayMode((PlayMode)evt.newValue);
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
});
|
|
|
|
playModeField?.schedule.Execute(() =>
|
|
{
|
|
if (playModeEnum?.value == null) return;
|
|
var playMode = (PlayMode)playModeEnum.value;
|
|
UpdatePlayMode(playMode);
|
|
});
|
|
|
|
void UpdatePlayMode(PlayMode playMode)
|
|
{
|
|
bool hasLoops = target != null && target.hasLoops;
|
|
|
|
loopDelayField.SetEnabled(hasLoops);
|
|
extraRow.SetStyleDisplay(playMode == PlayMode.Spring || playMode == PlayMode.Shake ? DisplayStyle.Flex : DisplayStyle.None);
|
|
elasticityField.SetStyleDisplay(playMode == PlayMode.Spring ? DisplayStyle.Flex : DisplayStyle.None);
|
|
fadeOutShake.SetStyleDisplay(playMode == PlayMode.Shake ? DisplayStyle.Flex : DisplayStyle.None);
|
|
|
|
List<Texture2D> animatedIconTextures;
|
|
switch (playMode)
|
|
{
|
|
case PlayMode.Normal:
|
|
animatedIconTextures = hasLoops ? EditorSpriteSheets.EditorUI.Icons.Loop : EditorSpriteSheets.EditorUI.Icons.OneShot;
|
|
playModeEnum.SetTooltip("Normal - current value goes from start value and target value");
|
|
break;
|
|
case PlayMode.PingPong:
|
|
animatedIconTextures = hasLoops ? EditorSpriteSheets.EditorUI.Icons.PingPong : EditorSpriteSheets.EditorUI.Icons.PingPongOnce;
|
|
playModeEnum.SetTooltip("PingPong - current value goes between start and target values back and forth");
|
|
break;
|
|
case PlayMode.Spring:
|
|
animatedIconTextures = EditorSpriteSheets.EditorUI.Icons.Spring;
|
|
playModeEnum.SetTooltip("Spring - current value goes between start and target values back and forth and returns to the start value as if connected by a spring");
|
|
break;
|
|
case PlayMode.Shake:
|
|
animatedIconTextures = EditorSpriteSheets.EditorUI.Icons.Shake;
|
|
playModeEnum.SetTooltip("Shake - current value randomly 'shakes' between start and target values back and forth and returns to the start value");
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(playMode), playMode, null);
|
|
}
|
|
|
|
playModeField.SetIcon(animatedIconTextures);
|
|
playModeField.iconReaction.Play();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EaseMode
|
|
|
|
easeModeEnum?.RegisterValueChangedCallback(evt =>
|
|
{
|
|
try
|
|
{
|
|
UpdateEaseMode((EaseMode)evt.newValue);
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
});
|
|
easeModeField.schedule.Execute(() =>
|
|
{
|
|
if (easeModeEnum?.value == null) return;
|
|
var easeMode = (EaseMode)easeModeEnum.value;
|
|
UpdateEaseMode(easeMode);
|
|
});
|
|
|
|
void UpdateEaseMode(EaseMode easeMode)
|
|
{
|
|
easeField.SetStyleDisplay(easeMode == EaseMode.Ease ? DisplayStyle.Flex : DisplayStyle.None);
|
|
animationCurveField.SetStyleDisplay(easeMode == EaseMode.AnimationCurve ? DisplayStyle.Flex : DisplayStyle.None);
|
|
}
|
|
|
|
#endregion
|
|
|
|
return drawer;
|
|
}
|
|
|
|
private static FluidField newStartDelayField
|
|
{
|
|
get
|
|
{
|
|
var value =
|
|
new FloatField { bindingPath = "StartDelay" }
|
|
.SetTooltip("Animation start delay (seconds)");
|
|
|
|
var randomValue =
|
|
new PropertyField { bindingPath = "RandomStartDelay" }
|
|
.SetTooltip("Random start delay interval [min]...[max] for the animation");
|
|
|
|
var useRandom = new Toggle { bindingPath = "UseRandomStartDelay" };
|
|
|
|
FluidField field = NewRandomField
|
|
(
|
|
"Start Delay",
|
|
value,
|
|
randomValue,
|
|
useRandom
|
|
);
|
|
|
|
// field.SetAnimatedIcon(Generic.GetTextures(Generic.AnimationName.StartDelay));
|
|
|
|
return field;
|
|
}
|
|
}
|
|
|
|
private static FluidField newDurationField
|
|
{
|
|
get
|
|
{
|
|
var value =
|
|
new FloatField { bindingPath = "Duration" }
|
|
.SetTooltip("Animation duration (seconds)");
|
|
|
|
var randomValue =
|
|
new PropertyField { bindingPath = "RandomDuration" }
|
|
.SetTooltip("Random animation duration interval [min]...[max] for the animation");
|
|
|
|
var useRandom = new Toggle { bindingPath = "UseRandomDuration" };
|
|
|
|
FluidField field = NewRandomField
|
|
(
|
|
"Duration",
|
|
value,
|
|
randomValue,
|
|
useRandom
|
|
);
|
|
|
|
// field.SetAnimatedIcon(Generic.GetTextures(Generic.AnimationName.Duration));
|
|
|
|
return field;
|
|
}
|
|
}
|
|
|
|
private static FluidField newLoopsField
|
|
{
|
|
get
|
|
{
|
|
var value =
|
|
new IntegerField { bindingPath = "Loops" }
|
|
.SetTooltip("Number of loops the animation needs to perform before it stops playing and finishes (-1 means infinite loops)");
|
|
|
|
var randomValue =
|
|
new PropertyField { bindingPath = "RandomLoops" }
|
|
.SetTooltip("Random number of loops interval [min]...[max] for the animation");
|
|
|
|
var useRandom = new Toggle { bindingPath = "UseRandomLoops" };
|
|
|
|
FluidField field = NewRandomField
|
|
(
|
|
"Loops",
|
|
value,
|
|
randomValue,
|
|
useRandom
|
|
);
|
|
|
|
// field.SetAnimatedIcon(EditorMicroAnimations.Dween. GetTextures(EditorMicroAnimations.Dween. AnimationName.Loop));
|
|
|
|
return field;
|
|
}
|
|
}
|
|
|
|
private static FluidField newLoopDelayField
|
|
{
|
|
get
|
|
{
|
|
var value =
|
|
new FloatField { bindingPath = "LoopDelay" }
|
|
.SetTooltip("Time delay between loops (seconds)");
|
|
|
|
var randomValue =
|
|
new PropertyField { bindingPath = "RandomLoopDelay" }
|
|
.SetTooltip("Random delay interval [min]...[max] between loops");
|
|
|
|
var useRandom = new Toggle { bindingPath = "UseRandomLoopDelay" };
|
|
|
|
FluidField field = NewRandomField
|
|
(
|
|
"Loop Delay",
|
|
value,
|
|
randomValue,
|
|
useRandom
|
|
);
|
|
|
|
// field.SetAnimatedIcon(Generic.GetTextures(Generic.AnimationName.DelayBetweenLoops));
|
|
|
|
return field;
|
|
}
|
|
}
|
|
|
|
private static FluidField NewRandomField
|
|
(
|
|
string fieldName,
|
|
VisualElement value,
|
|
VisualElement randomValue,
|
|
Toggle useRandom
|
|
)
|
|
{
|
|
value.ResetLayout();
|
|
useRandom.SetStyleDisplay(DisplayStyle.None);
|
|
|
|
FluidToggleButtonTab randomButton =
|
|
FluidToggleButtonTab.Get(EditorSpriteSheets.EditorUI.Icons.Dice)
|
|
.SetTooltip("Random Value")
|
|
.SetElementSize(ElementSize.Normal)
|
|
.SetTabPosition(TabPosition.FloatingTab)
|
|
.SetOnClick(() => useRandom.value = !useRandom.value);
|
|
|
|
FluidField field =
|
|
FluidField.Get()
|
|
.AddFieldContent(value)
|
|
.AddFieldContent(randomValue)
|
|
.AddFieldContent(useRandom)
|
|
.AddInfoElement(randomButton);
|
|
|
|
useRandom.RegisterValueChangedCallback(evt => VisualUpdate(evt.newValue));
|
|
VisualUpdate(useRandom.value);
|
|
field.schedule.Execute(() => VisualUpdate(useRandom.value));
|
|
return field;
|
|
|
|
void VisualUpdate(bool useRandomValue)
|
|
{
|
|
field.SetLabelText($"{(useRandomValue ? "Random " : "")}{fieldName}");
|
|
value.SetStyleDisplay(useRandomValue ? DisplayStyle.None : DisplayStyle.Flex);
|
|
randomValue.SetStyleDisplay(useRandomValue ? DisplayStyle.Flex : DisplayStyle.None);
|
|
randomButton.isOn = useRandomValue;
|
|
}
|
|
}
|
|
}
|
|
}
|