You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
16 KiB
304 lines
16 KiB
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace UnityEditor.VFX
|
|
{
|
|
[CustomEditor(typeof(VFXBasicSpawner))]
|
|
[CanEditMultipleObjects]
|
|
class VFXBasicSpawnerEditor : Editor
|
|
{
|
|
class Styles
|
|
{
|
|
public static GUIContent delayMode = new GUIContent("Delay Mode", "Activate Delay before or after loop");
|
|
public static GUIContent delayRandom = new GUIContent("Delay Random", "Enable or disable random mode for delay.");
|
|
public static GUIContent delayBeforeRandom = new GUIContent("Delay Before Random", "Enable or disable random mode for delay before loop.");
|
|
public static GUIContent delayAfterRandom = new GUIContent("Delay After Random", "Enable or disable random mode for delay after loop.");
|
|
}
|
|
|
|
SerializedProperty m_LoopDurationProperty;
|
|
SerializedProperty m_LoopCountProperty;
|
|
SerializedProperty m_DelayBeforeLoopProperty;
|
|
SerializedProperty m_DelayAfterLoopProperty;
|
|
|
|
private void OnEnable()
|
|
{
|
|
m_LoopDurationProperty = serializedObject.FindProperty("loopDuration");
|
|
m_LoopCountProperty = serializedObject.FindProperty("loopCount");
|
|
m_DelayBeforeLoopProperty = serializedObject.FindProperty("delayBeforeLoop");
|
|
m_DelayAfterLoopProperty = serializedObject.FindProperty("delayAfterLoop");
|
|
}
|
|
|
|
enum DisplayedDelayMode
|
|
{
|
|
None,
|
|
AfterLoop,
|
|
BeforeLoop,
|
|
BeforeAndAfterLoop
|
|
}
|
|
|
|
struct DelaySettings
|
|
{
|
|
public VFXBasicSpawner.DelayMode delayBeforeLoop;
|
|
public VFXBasicSpawner.DelayMode delayAfterLoop;
|
|
}
|
|
|
|
struct DisplayedDelaySettings
|
|
{
|
|
public DisplayedDelayMode mode;
|
|
public bool? randomBefore;
|
|
public bool? randomAfter;
|
|
}
|
|
|
|
private static readonly KeyValuePair<DelaySettings, DisplayedDelaySettings>[] s_Modes =
|
|
{
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.None, delayAfterLoop = VFXBasicSpawner.DelayMode.None }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.None, randomBefore = null, randomAfter = null }),
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.None, delayAfterLoop = VFXBasicSpawner.DelayMode.Constant }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.AfterLoop, randomBefore = null, randomAfter = false }),
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.None, delayAfterLoop = VFXBasicSpawner.DelayMode.Random }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.AfterLoop, randomBefore = null, randomAfter = true }),
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.Constant, delayAfterLoop = VFXBasicSpawner.DelayMode.None }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.BeforeLoop, randomBefore = false, randomAfter = null }),
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.Constant, delayAfterLoop = VFXBasicSpawner.DelayMode.Constant }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.BeforeAndAfterLoop, randomBefore = false, randomAfter = false }),
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.Constant, delayAfterLoop = VFXBasicSpawner.DelayMode.Random }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.BeforeAndAfterLoop, randomBefore = false, randomAfter = true }),
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.Random, delayAfterLoop = VFXBasicSpawner.DelayMode.None }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.BeforeLoop, randomBefore = true, randomAfter = null }),
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.Random, delayAfterLoop = VFXBasicSpawner.DelayMode.Constant }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.BeforeAndAfterLoop, randomBefore = true, randomAfter = false }),
|
|
new KeyValuePair<DelaySettings, DisplayedDelaySettings>(new DelaySettings(){ delayBeforeLoop = VFXBasicSpawner.DelayMode.Random, delayAfterLoop = VFXBasicSpawner.DelayMode.Random }, new DisplayedDelaySettings() { mode = DisplayedDelayMode.BeforeAndAfterLoop, randomBefore = true, randomAfter = true }),
|
|
};
|
|
|
|
struct RandomAvailable
|
|
{
|
|
public bool before;
|
|
public bool after;
|
|
}
|
|
private static readonly KeyValuePair<DisplayedDelayMode, RandomAvailable>[] s_RandomAvailable = s_Modes.GroupBy(o => o.Value.mode).Select(o =>
|
|
{
|
|
return new KeyValuePair<DisplayedDelayMode, RandomAvailable>(o.Key, new RandomAvailable()
|
|
{
|
|
before = o.Any(k => k.Value.randomBefore != null),
|
|
after = o.Any(k => k.Value.randomAfter != null)
|
|
});
|
|
}).ToArray();
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
serializedObject.Update();
|
|
|
|
var referenceContext = serializedObject.targetObject as VFXContext;
|
|
var resource = referenceContext.GetResource();
|
|
GUI.enabled = resource != null ? resource.IsAssetEditable() : true;
|
|
|
|
DisplayName(referenceContext);
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.PropertyField(m_LoopDurationProperty);
|
|
EditorGUILayout.PropertyField(m_LoopCountProperty);
|
|
|
|
bool applyModifiedProperty = false;
|
|
|
|
if (m_DelayBeforeLoopProperty.hasMultipleDifferentValues || m_DelayAfterLoopProperty.hasMultipleDifferentValues)
|
|
{
|
|
//Default GUI when multi editing
|
|
EditorGUILayout.PropertyField(m_DelayBeforeLoopProperty);
|
|
EditorGUILayout.PropertyField(m_DelayAfterLoopProperty);
|
|
applyModifiedProperty = EditorGUI.EndChangeCheck();
|
|
}
|
|
else
|
|
{
|
|
//Smarter way to display these option : allowing an efficient resync slot
|
|
var delayBefore = (VFXBasicSpawner.DelayMode)m_DelayBeforeLoopProperty.enumValueIndex;
|
|
var delayAfter = (VFXBasicSpawner.DelayMode)m_DelayAfterLoopProperty.enumValueIndex;
|
|
|
|
var currentState = s_Modes.First(o => o.Key.delayBeforeLoop == delayBefore && o.Key.delayAfterLoop == delayAfter).Value;
|
|
|
|
currentState.mode = (DisplayedDelayMode)EditorGUILayout.EnumPopup(Styles.delayMode, currentState.mode);
|
|
bool shouldIndicateWhichRandom = currentState.randomBefore != null && currentState.randomAfter != null;
|
|
if (currentState.randomBefore.HasValue)
|
|
currentState.randomBefore = EditorGUILayout.Toggle(shouldIndicateWhichRandom ? Styles.delayBeforeRandom : Styles.delayRandom, (bool)currentState.randomBefore);
|
|
if (currentState.randomAfter.HasValue)
|
|
currentState.randomAfter = EditorGUILayout.Toggle(shouldIndicateWhichRandom ? Styles.delayAfterRandom : Styles.delayRandom, (bool)currentState.randomAfter);
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
//Copy random setting if other random hasn't a value
|
|
if (currentState.randomBefore.HasValue && !currentState.randomAfter.HasValue)
|
|
currentState.randomAfter = currentState.randomBefore;
|
|
if (!currentState.randomBefore.HasValue && currentState.randomAfter.HasValue)
|
|
currentState.randomBefore = currentState.randomAfter;
|
|
|
|
//Cancel useless random setting or reset to false if random is used by null is provided
|
|
var randomAvailable = s_RandomAvailable.First(o => o.Key == currentState.mode);
|
|
if (!randomAvailable.Value.before)
|
|
currentState.randomBefore = null;
|
|
else if (!currentState.randomBefore.HasValue)
|
|
currentState.randomBefore = false;
|
|
|
|
if (!randomAvailable.Value.after)
|
|
currentState.randomAfter = null;
|
|
else if (!currentState.randomAfter.HasValue)
|
|
currentState.randomAfter = false;
|
|
|
|
var actualSetting = s_Modes.First(o =>
|
|
o.Value.mode == currentState.mode
|
|
&& (o.Value.randomBefore == currentState.randomBefore)
|
|
&& (o.Value.randomAfter == currentState.randomAfter)).Key;
|
|
|
|
m_DelayBeforeLoopProperty.enumValueIndex = (int)actualSetting.delayBeforeLoop;
|
|
m_DelayAfterLoopProperty.enumValueIndex = (int)actualSetting.delayAfterLoop;
|
|
applyModifiedProperty = true;
|
|
}
|
|
}
|
|
|
|
if (applyModifiedProperty)
|
|
{
|
|
if (serializedObject.ApplyModifiedProperties())
|
|
{
|
|
foreach (var context in targets.OfType<VFXModel>())
|
|
{
|
|
// notify that something changed.
|
|
context.Invalidate(VFXModel.InvalidationCause.kSettingChanged);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DisplayName(VFXContext context)
|
|
{
|
|
var label = string.IsNullOrEmpty(context.label) ? context.letter.ToString() : context.label;
|
|
GUILayout.Label(label, VFXSlotContainerEditor.Styles.spawnStyle);
|
|
}
|
|
}
|
|
|
|
[VFXHelpURL("Context-Spawn")]
|
|
[VFXInfo(name = "Spawn", category = "#0Common")]
|
|
class VFXBasicSpawner : VFXContext
|
|
{
|
|
public enum DelayMode
|
|
{
|
|
None,
|
|
Constant,
|
|
Random
|
|
}
|
|
|
|
public enum LoopMode
|
|
{
|
|
Infinite,
|
|
Constant,
|
|
Random
|
|
}
|
|
|
|
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField]
|
|
private LoopMode loopDuration = LoopMode.Infinite;
|
|
|
|
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField]
|
|
private LoopMode loopCount = LoopMode.Infinite;
|
|
|
|
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField]
|
|
private DelayMode delayBeforeLoop = DelayMode.None;
|
|
|
|
[VFXSetting(VFXSettingAttribute.VisibleFlags.InInspector), SerializeField]
|
|
private DelayMode delayAfterLoop = DelayMode.None;
|
|
|
|
public VFXBasicSpawner() : base(VFXContextType.Spawner, VFXDataType.SpawnEvent, VFXDataType.SpawnEvent) { }
|
|
public override string name { get { return "Spawn"; } }
|
|
|
|
protected override int inputFlowCount
|
|
{
|
|
get
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
protected override IEnumerable<VFXPropertyWithValue> inputProperties
|
|
{
|
|
get
|
|
{
|
|
foreach (var property in base.inputProperties)
|
|
yield return property;
|
|
|
|
if (loopDuration == LoopMode.Constant)
|
|
yield return new VFXPropertyWithValue(new VFXProperty(typeof(float), "LoopDuration"), 0.1f);
|
|
else if (loopDuration == LoopMode.Random)
|
|
yield return new VFXPropertyWithValue(new VFXProperty(typeof(Vector2), "LoopDuration"), new Vector2(1.0f, 3.0f));
|
|
|
|
if (loopCount == LoopMode.Constant)
|
|
yield return new VFXPropertyWithValue(new VFXProperty(typeof(int), "LoopCount"), 1);
|
|
else if (loopCount == LoopMode.Random)
|
|
yield return new VFXPropertyWithValue(new VFXProperty(typeof(Vector2), "LoopCount"), new Vector2(1.0f, 3.0f)); //Int2 isn't supported yet
|
|
|
|
if (delayBeforeLoop == DelayMode.Constant)
|
|
yield return new VFXPropertyWithValue(new VFXProperty(typeof(float), "DelayBeforeLoop"), 0.1f);
|
|
else if (delayBeforeLoop == DelayMode.Random)
|
|
yield return new VFXPropertyWithValue(new VFXProperty(typeof(Vector2), "DelayBeforeLoop"), new Vector2(0.1f, 0.3f));
|
|
|
|
if (delayAfterLoop == DelayMode.Constant)
|
|
yield return new VFXPropertyWithValue(new VFXProperty(typeof(float), "DelayAfterLoop"), 0.1f);
|
|
else if (delayAfterLoop == DelayMode.Random)
|
|
yield return new VFXPropertyWithValue(new VFXProperty(typeof(Vector2), "DelayAfterLoop"), new Vector2(0.1f, 0.3f));
|
|
}
|
|
}
|
|
|
|
public override IEnumerable<VFXAttributeInfo> attributes
|
|
{
|
|
get
|
|
{
|
|
yield return new VFXAttributeInfo(VFXAttribute.SpawnCount, VFXAttributeMode.ReadWrite);
|
|
foreach (var attribute in base.attributes)
|
|
yield return attribute;
|
|
}
|
|
}
|
|
|
|
static VFXExpression RandomFromVector2(VFXExpression input, RandId randId)
|
|
{
|
|
return VFXOperatorUtility.Lerp(input.x, input.y, new VFXExpressionRandom(false, randId));
|
|
}
|
|
|
|
public override VFXExpressionMapper GetExpressionMapper(VFXDeviceTarget target)
|
|
{
|
|
if (target == VFXDeviceTarget.CPU)
|
|
{
|
|
var mapper = VFXExpressionMapper.FromBlocks(activeFlattenedChildrenWithImplicit);
|
|
|
|
var mapperFromContext = new VFXExpressionMapper();
|
|
mapperFromContext.AddExpressionsFromSlotContainer(this, -1);
|
|
|
|
if (loopDuration != LoopMode.Infinite)
|
|
{
|
|
var expression = mapperFromContext.FromNameAndId("LoopDuration", -1);
|
|
if (loopDuration == LoopMode.Random)
|
|
expression = RandomFromVector2(expression, new RandId(this, 0));
|
|
mapper.AddExpression(expression, "LoopDuration", -1);
|
|
}
|
|
|
|
if (loopCount != LoopMode.Infinite)
|
|
{
|
|
var expression = mapperFromContext.FromNameAndId("LoopCount", -1);
|
|
if (loopCount == LoopMode.Random)
|
|
expression = new VFXExpressionCastFloatToInt(RandomFromVector2(expression, new RandId(this, 1)));
|
|
mapper.AddExpression(expression, "LoopCount", -1);
|
|
}
|
|
|
|
if (delayBeforeLoop != DelayMode.None)
|
|
{
|
|
var expression = mapperFromContext.FromNameAndId("DelayBeforeLoop", -1);
|
|
if (delayBeforeLoop == DelayMode.Random)
|
|
expression = RandomFromVector2(expression, new RandId(this, 2));
|
|
mapper.AddExpression(expression, "DelayBeforeLoop", -1);
|
|
}
|
|
|
|
if (delayAfterLoop != DelayMode.None)
|
|
{
|
|
var expression = mapperFromContext.FromNameAndId("DelayAfterLoop", -1);
|
|
if (delayAfterLoop == DelayMode.Random)
|
|
expression = RandomFromVector2(expression, new RandId(this, 3));
|
|
mapper.AddExpression(expression, "DelayAfterLoop", -1);
|
|
}
|
|
return mapper;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override bool CanBeCompiled()
|
|
{
|
|
return outputContexts.Any(c => c.CanBeCompiled());
|
|
}
|
|
}
|
|
}
|