#if UNITY_EDITOR using UnityEngine; using UnityEditor; using UnityEngine.UIElements; using System.Collections.Generic; #if UNITY_2021 using UnityEditor.UIElements; #endif namespace GSpawn { public enum SegmentsObjectSpawnCellMode { SpawnGuide = 0, Grid } public enum SegmentsObjectSpawnJitterMode { None = 0, All, HeightRange } public enum SegmentsObjectSpawnHeightMode { Constant = 0, Random, Pattern } public enum SegmentsObjectSpawnCornerConnection { Normal = 0, Overlap, Gap } public enum SegmentsObjectSpawnProjectionMode { None = 0, Terrains } public enum SegmentsObjectSpawnMajorAxis { Longest = 0, Shortest } public enum SegmentsObjectSpawnFillMode { Solid = 0, Border } public enum SegmentsObjectSpawnPrefabPickMode { SpawnGuide = 0, Random, HeightRange, } public class SegmentsObjectSpawnSettingsProfile : Profile { [SerializeField] private SegmentsObjectSpawnCellMode _cellMode = defaultCellMode; [SerializeField] private bool _useSceneGridCellSize = defaultUseSceneGridCellSize; [SerializeField] private Vector3 _gridCellSize = defaultGridCellSize; [SerializeField] private SegmentsObjectSpawnMajorAxis _majorAxis = defaultMajorAxis; [SerializeField] private SegmentsObjectSpawnCornerConnection _cornerConnection = defaultCornerConnection; [SerializeField] private bool _rotateAtCorners = defaultRotateAtCorners; [SerializeField] private float _objectSkipChance = defaultObjectSkipChance; [SerializeField] private float _horizontalPadding = defaultHorizontalPadding; [SerializeField] private float _verticalPadding = defaultVerticalPadding; [SerializeField] private float _volumelessObjectSize = defaultVolumelessObjectSize; [SerializeField] private bool _avoidOverlaps = defaultAvoidOverlaps; [SerializeField] private int _maxSegmentLength = defaultMaxSegmentLength; [SerializeField] private SegmentsObjectSpawnHeightMode _heightMode = defaultHeightMode; [SerializeField] private int _defaultHeight = defaultDefaultHeight; [SerializeField] private int _heightRaiseAmount = defaultHeightRaiseAmount; [SerializeField] private int _heightLowerAmount = defaultHeightLowerAmount; [SerializeField] private int _minRandomHeight = defaultMinRandomHeight; [SerializeField] private int _maxRandomHeight = defaultMaxRandomHeight; [SerializeField] private IntPatternWrapMode _heightPatternWrapMode = defaultHeightPatternWrapMode; [SerializeField] private IntPattern _heightPattern = null; // Note: Must be null initially to avoid calling SO ctor. [SerializeField] private SegmentsObjectSpawnJitterMode _jitterMode = defaultJitterMode; [SerializeField] private float _minJitter = defaultMinJitter; [SerializeField] private float _maxJitter = defaultMaxJitter; [SerializeField] private int _minJitterHeight = defaultMinJitterHeight; [SerializeField] private int _maxJitterHeight = defaultMaxJitterHeight; [SerializeField] private SegmentsObjectSpawnFillMode _fillMode = defaultFillMode; [SerializeField] private int _beginBorderWidth = defaultBeginBorderWidth; [SerializeField] private int _endBorderWidth = defaultEndBorderWidth; [SerializeField] private int _topBorderWidth = defaultTopBorderWidth; [SerializeField] private int _bottomBorderWidth = defaultBottomBorderWidth; [SerializeField] private int _segmentCapBorderWidth = defaultSegmentCapBorderWidth; [SerializeField] private SegmentsObjectSpawnPrefabPickMode _prefabPickMode = defaultPrefabPickMode; [SerializeField] private string _randomPrefabProfileName = defaultRandomPrefabProfileName; [SerializeField] private string _heightRangePrefabProfileName = defaultHeightRangePrefabProfileName; [SerializeField] private SegmentsObjectSpawnProjectionMode _projectionMode = defaultProjectionMode; private SerializedObject _serializedObject; private SerializedObject serializedObject { get { if (_serializedObject == null) _serializedObject = new SerializedObject(this); return _serializedObject; } } public SegmentsObjectSpawnCellMode cellMode { get { return _cellMode; } set { UndoEx.record(this); _cellMode = value; EditorUtility.SetDirty(this); } } public bool useSceneGridCellSize { get { return _useSceneGridCellSize; } set { UndoEx.record(this); _useSceneGridCellSize = value; EditorUtility.SetDirty(this); } } public Vector3 gridCellSize { get { return _gridCellSize; } set { UndoEx.record(this); _gridCellSize = Vector3.Max(value, Vector3Ex.create(DefaultSystemValues.minGridCellSize)); EditorUtility.SetDirty(this); } } public SegmentsObjectSpawnMajorAxis majorAxis { get { return _majorAxis; } set { UndoEx.record(this); _majorAxis = value; EditorUtility.SetDirty(this); } } public SegmentsObjectSpawnCornerConnection cornerConnection { get { return _cornerConnection; } set { UndoEx.record(this); _cornerConnection = value; EditorUtility.SetDirty(this); } } public bool rotateAtCorners { get { return _rotateAtCorners; } set { UndoEx.record(this); _rotateAtCorners = value; EditorUtility.SetDirty(this); } } public float objectSkipChance { get { return _objectSkipChance; } set { UndoEx.record(this); _objectSkipChance = Mathf.Clamp01(value); EditorUtility.SetDirty(this); } } public float horizontalPadding { get { return _horizontalPadding; } set { UndoEx.record(this); _horizontalPadding = value; EditorUtility.SetDirty(this); } } public float verticalPadding { get { return _verticalPadding; } set { UndoEx.record(this); _verticalPadding = value; EditorUtility.SetDirty(this); } } public float volumlessObjectSize { get { return _volumelessObjectSize; } set { UndoEx.record(this); _volumelessObjectSize = Mathf.Max(1e-1f, value); EditorUtility.SetDirty(this); } } public bool avoidOverlaps { get { return _avoidOverlaps; } set { UndoEx.record(this); _avoidOverlaps = value; EditorUtility.SetDirty(this); } } public int maxSegmentLength { get { return _maxSegmentLength; } set { UndoEx.record(this); _maxSegmentLength = Mathf.Max(2, value); EditorUtility.SetDirty(this); } } public SegmentsObjectSpawnHeightMode heightMode { get { return _heightMode; } set { UndoEx.record(this); _heightMode = value; EditorUtility.SetDirty(this); } } public int defaultHeight { get { return _defaultHeight; } set { UndoEx.record(this); _defaultHeight = value; EditorUtility.SetDirty(this); } } public int heightRaiseAmount { get { return _heightRaiseAmount; } set { UndoEx.record(this); _heightRaiseAmount = Mathf.Max(1, value); EditorUtility.SetDirty(this); } } public int heightLowerAmount { get { return _heightLowerAmount; } set { UndoEx.record(this); _heightLowerAmount = Mathf.Max(1, value); EditorUtility.SetDirty(this); } } public int minRandomHeight { get { return _minRandomHeight; } set { UndoEx.record(this); _minRandomHeight = Mathf.Min(value, _maxRandomHeight); EditorUtility.SetDirty(this); } } public int maxRandomHeight { get { return _maxRandomHeight; } set { UndoEx.record(this); _maxRandomHeight = Mathf.Max(value, _minRandomHeight); EditorUtility.SetDirty(this); } } public IntPatternWrapMode heightPatternWrapMode { get { return _heightPatternWrapMode; } set { UndoEx.record(this); _heightPatternWrapMode = value; EditorUtility.SetDirty(this); } } public IntPattern heightPattern { get { if (_heightPattern == null) _heightPattern = defaultHeightPattern; return _heightPattern; } set { UndoEx.record(this); _heightPattern = value; EditorUtility.SetDirty(this); } } public SegmentsObjectSpawnJitterMode jitterMode { get { return _jitterMode; } set { UndoEx.record(this); _jitterMode = value; EditorUtility.SetDirty(this); } } public float minJitter { get { return _minJitter; } set { UndoEx.record(this); _minJitter = Mathf.Max(value, 0.0f); if (_maxJitter < _minJitter) _maxJitter = _minJitter; EditorUtility.SetDirty(this); } } public float maxJitter { get { return _maxJitter; } set { UndoEx.record(this); _maxJitter = Mathf.Max(value, 0.0f); if (_minJitter > _maxJitter) _minJitter = _maxJitter; EditorUtility.SetDirty(this); } } public int minJitterHeight { get { return _minJitterHeight; } set { UndoEx.record(this); _minJitterHeight = Mathf.Min(value, _maxJitterHeight); EditorUtility.SetDirty(this); } } public int maxJitterHeight { get { return _maxJitterHeight; } set { UndoEx.record(this); _maxJitterHeight = Mathf.Max(value, _minJitterHeight); EditorUtility.SetDirty(this); } } public SegmentsObjectSpawnFillMode fillMode { get { return _fillMode; } set { UndoEx.record(this); _fillMode = value; EditorUtility.SetDirty(this); } } public int beginBorderWidth { get { return _beginBorderWidth; } set { UndoEx.record(this); _beginBorderWidth = Mathf.Max(0, value); EditorUtility.SetDirty(this); } } public int endBorderWidth { get { return _endBorderWidth; } set { UndoEx.record(this); _endBorderWidth = Mathf.Max(0, value); EditorUtility.SetDirty(this); } } public int topBorderWidth { get { return _topBorderWidth; } set { UndoEx.record(this); _topBorderWidth = Mathf.Max(0, value); EditorUtility.SetDirty(this); } } public int bottomBorderWidth { get { return _bottomBorderWidth; } set { UndoEx.record(this); _bottomBorderWidth = Mathf.Max(0, value); EditorUtility.SetDirty(this); } } public int segmentCapBorderWidth { get { return _segmentCapBorderWidth; } set { UndoEx.record(this); _segmentCapBorderWidth = Mathf.Max(0, value); EditorUtility.SetDirty(this); } } public SegmentsObjectSpawnPrefabPickMode prefabPickMode { get { return _prefabPickMode; } set { UndoEx.record(this); _prefabPickMode = value; EditorUtility.SetDirty(this); } } public RandomPrefabProfile randomPrefabProfile { get { var profile = RandomPrefabProfileDb.instance.findProfile(_randomPrefabProfileName); if (profile == null) profile = RandomPrefabProfileDb.instance.defaultProfile; return profile; } } public IntRangePrefabProfile heightRangePrefabProfile { get { var profile = IntRangePrefabProfileDb.instance.findProfile(_heightRangePrefabProfileName); if (profile == null) profile = IntRangePrefabProfileDb.instance.defaultProfile; return profile; } } public SegmentsObjectSpawnProjectionMode projectionMode { get { return _projectionMode; } set { UndoEx.record(this); _projectionMode = value; EditorUtility.SetDirty(this); } } public static SegmentsObjectSpawnCellMode defaultCellMode { get { return SegmentsObjectSpawnCellMode.SpawnGuide; } } public static bool defaultUseSceneGridCellSize { get { return true; } } public static Vector3 defaultGridCellSize { get { return Vector3.one; } } public static SegmentsObjectSpawnMajorAxis defaultMajorAxis { get { return SegmentsObjectSpawnMajorAxis.Longest; } } public static SegmentsObjectSpawnCornerConnection defaultCornerConnection { get { return SegmentsObjectSpawnCornerConnection.Normal; } } public static bool defaultRotateAtCorners { get { return false; } } public static float defaultObjectSkipChance { get { return 0.0f; } } public static float defaultHorizontalPadding { get { return 0.0f; } } public static float defaultVerticalPadding { get { return 0.0f; } } public static float defaultVolumelessObjectSize { get { return 1.0f; } } public static bool defaultAvoidOverlaps { get { return true; } } public static int defaultMaxSegmentLength { get { return 200; } } public static SegmentsObjectSpawnHeightMode defaultHeightMode { get { return SegmentsObjectSpawnHeightMode.Constant; } } public static int defaultDefaultHeight { get { return 1; } } public static int defaultHeightRaiseAmount { get { return 1; } } public static int defaultHeightLowerAmount { get { return 1; } } public static int defaultMinRandomHeight { get { return 1; } } public static int defaultMaxRandomHeight { get { return 5; } } public static IntPatternWrapMode defaultHeightPatternWrapMode { get { return IntPatternWrapMode.Repeat; } } public static IntPattern defaultHeightPattern { get { return IntPatternDb.instance.defaultPattern; } } public static SegmentsObjectSpawnJitterMode defaultJitterMode { get { return SegmentsObjectSpawnJitterMode.None; } } public static float defaultMinJitter { get { return 0.0f; } } public static float defaultMaxJitter { get { return 0.1f; } } public static int defaultMinJitterHeight { get { return 1; } } public static int defaultMaxJitterHeight { get { return 1; } } public static SegmentsObjectSpawnFillMode defaultFillMode { get { return SegmentsObjectSpawnFillMode.Solid; } } public static int defaultBeginBorderWidth { get { return 1; } } public static int defaultEndBorderWidth { get { return 1; } } public static int defaultTopBorderWidth { get { return 1; } } public static int defaultBottomBorderWidth { get { return 1; } } public static int defaultSegmentCapBorderWidth { get { return 0; } } public static SegmentsObjectSpawnPrefabPickMode defaultPrefabPickMode { get { return SegmentsObjectSpawnPrefabPickMode.SpawnGuide; } } public static string defaultRandomPrefabProfileName { get { return RandomPrefabProfileDb.defaultProfileName; } } public static string defaultHeightRangePrefabProfileName { get { return IntRangePrefabProfileDb.defaultProfileName; } } public static SegmentsObjectSpawnProjectionMode defaultProjectionMode { get { return SegmentsObjectSpawnProjectionMode.None; } } public void onIntPatternsWillBeDeleted(List patterns) { if (patterns.Contains(heightPattern)) { UndoEx.record(this); _heightPattern = IntPatternDb.instance.defaultPattern; } } public void buildUI(VisualElement parent) { const float labelWidth = 150.0f; //createCellModeControls(parent, labelWidth); createMiscControls(parent, labelWidth); var separator = UI.createRowSeparator(parent); separator.name = "Separator_Misc_Height"; createHeightModeControls(parent, labelWidth); separator = UI.createRowSeparator(parent); separator.name = "Separator_Height_Jitter"; createJitterModeControls(parent, labelWidth); separator = UI.createRowSeparator(parent); separator.name = "Separator_Jitter_FillMode"; createFillModeControls(parent, labelWidth); separator = UI.createRowSeparator(parent); separator.name = "Separator_FillMode_PrefabPickMode"; createPrefabPickModeControls(parent, labelWidth); UI.createRowSeparator(parent); createProjectionModeControls(parent, labelWidth); UI.createUseDefaultsButton(() => useDefaults(), parent); } public void useDefaults() { cellMode = defaultCellMode; gridCellSize = defaultGridCellSize; useSceneGridCellSize = defaultUseSceneGridCellSize; majorAxis = defaultMajorAxis; cornerConnection = defaultCornerConnection; rotateAtCorners = defaultRotateAtCorners; objectSkipChance = defaultObjectSkipChance; horizontalPadding = defaultHorizontalPadding; verticalPadding = defaultVerticalPadding; volumlessObjectSize = defaultVolumelessObjectSize; avoidOverlaps = defaultAvoidOverlaps; maxSegmentLength = defaultMaxSegmentLength; heightMode = defaultHeightMode; defaultHeight = defaultDefaultHeight; heightRaiseAmount = defaultHeightRaiseAmount; heightLowerAmount = defaultHeightLowerAmount; minRandomHeight = defaultMinRandomHeight; maxRandomHeight = defaultMaxRandomHeight; heightPatternWrapMode = defaultHeightPatternWrapMode; heightPattern = defaultHeightPattern; jitterMode = defaultJitterMode; minJitter = defaultMinJitter; maxJitter = defaultMaxJitter; minJitterHeight = defaultMinJitterHeight; maxJitterHeight = defaultMaxJitterHeight; fillMode = defaultFillMode; beginBorderWidth = defaultBeginBorderWidth; endBorderWidth = defaultEndBorderWidth; topBorderWidth = defaultTopBorderWidth; bottomBorderWidth = defaultBottomBorderWidth; segmentCapBorderWidth = defaultSegmentCapBorderWidth; prefabPickMode = defaultPrefabPickMode; _randomPrefabProfileName = defaultRandomPrefabProfileName; _heightRangePrefabProfileName = defaultHeightRangePrefabProfileName; projectionMode = defaultProjectionMode; EditorUtility.SetDirty(this); } /* private void createCellModeControls(VisualElement parent, float labelWidth) { Vector3Field gridCellSizeField = null; Toggle useSceneGridCellSizeField = null; // Note: Currently used. Doesn't seem to work 100%. var cellModeField = UI.createEnumField(typeof(SegmentsObjectSpawnCellMode), "_cellMode", serializedObject, "Cell mode", "Allows you to specify the way in which the segment cells are calculated.", parent); cellModeField.setChildLabelWidth(labelWidth); cellModeField.RegisterValueChangedCallback(p => { gridCellSizeField.setDisplayVisible(cellMode == SegmentsObjectSpawnCellMode.Grid); useSceneGridCellSizeField.setDisplayVisible(cellMode == SegmentsObjectSpawnCellMode.Grid); }); gridCellSizeField = UI.createVector3Field("_gridCellSize", serializedObject, "Grid cell size", "When the cell mode is set to Grid, this field allows you to specify the grid cell size.", Vector3Ex.create(DefaultSystemValues.minGridCellSize), parent); gridCellSizeField.setChildLabelWidth(labelWidth); gridCellSizeField.setDisplayVisible(cellMode == SegmentsObjectSpawnCellMode.Grid); useSceneGridCellSizeField = UI.createToggle("_useSceneGridCellSize", serializedObject, "Use scene grid cell size", "If checked and the cell mode is set to Grid, the plugin will use the cell size of the scene grid. ", parent); useSceneGridCellSizeField.setChildLabelWidth(labelWidth); useSceneGridCellSizeField.setDisplayVisible(cellMode == SegmentsObjectSpawnCellMode.Grid); }*/ private void createMiscControls(VisualElement parent, float labelWidth) { VisualElement ctrl = UI.createEnumField(typeof(SegmentsObjectSpawnMajorAxis), "_majorAxis", serializedObject, "Major axis", "Allows you to specify the initial extension axis for the first segment in the chain.", parent); ctrl.setChildLabelWidth(labelWidth); ctrl = UI.createEnumField(typeof(SegmentsObjectSpawnCornerConnection), "_cornerConnection", serializedObject, "Corner connection", "Controls the way in which segments are connected at corners.", parent); ctrl.setChildLabelWidth(labelWidth); ctrl = UI.createToggle("_rotateAtCorners", serializedObject, "Rotate at corners", "If checked, the objects will be rotated at each 90 degree turn.", parent); ctrl.setChildLabelWidth(labelWidth); ctrl = UI.createFloatField("_objectSkipChance", serializedObject, "Object skip chance", "Specifies the probability of an object being skipped during the spawn process.", 0.0f, 1.0f, parent); ctrl.setChildLabelWidth(labelWidth); ctrl = UI.createFloatField("_horizontalPadding", serializedObject, "Horizontal padding", "The amount of padding applied horizontally (i.e. along the extension plane).", parent); ctrl.setChildLabelWidth(labelWidth); ctrl = UI.createFloatField("_verticalPadding", serializedObject, "Vertical padding", "The amount of padding applied vertically (i.e. perpendicular to the extension plane).", parent); ctrl.setChildLabelWidth(labelWidth); ctrl = UI.createFloatField("_volumelessObjectSize", serializedObject, "Volumeless object size", "The size that should be used for objects that don't have a volume.", 1e-1f, parent); ctrl.setChildLabelWidth(labelWidth); ctrl = UI.createToggle("_avoidOverlaps", serializedObject, "Avoid overlaps", "If this is checked, no objects will be created in places where they would overlap with already existing objects.", parent); ctrl.setChildLabelWidth(labelWidth); ctrl = UI.createIntegerField("_maxSegmentLength", serializedObject, "Max segment length", "The maximum length a segment can have. Useful to prevent " + "segments from getting too long for certain camera angles.", 2, parent); ctrl.setChildLabelWidth(labelWidth); } private void createHeightModeControls(VisualElement parent, float labelWidth) { var heightModeField = UI.createEnumField(typeof(SegmentsObjectSpawnHeightMode), "_heightMode", serializedObject, "Height mode", "Allows you to specify the way in which the segments' height is updated.", parent); heightModeField.setChildLabelWidth(labelWidth); IntegerField defaultHeightField = UI.createIntegerField("_defaultHeight", serializedObject, "Default height", "The default height that will be used when segment creation starts. " + "For height modes other than Constant, this acts as an offset/base height.", parent); defaultHeightField.setChildLabelWidth(labelWidth); IntegerField raiseAmountField = UI.createIntegerField("_heightRaiseAmount", serializedObject, "Raise amount", "Specifies how much the segments are raised when using the scroll wheel.", parent); raiseAmountField.setChildLabelWidth(labelWidth); IntegerField lowerAmountField = UI.createIntegerField("_heightLowerAmount", serializedObject, "Lower amount", "Specifies how much the segments are lowered when using the scroll wheel.", parent); lowerAmountField.setChildLabelWidth(labelWidth); IntegerField minRandomHeightField = UI.createIntegerField("_minRandomHeight", serializedObject, "Min height", "The minimum random height.", parent); minRandomHeightField.setChildLabelWidth(labelWidth); IntegerField maxRandomHeightField = UI.createIntegerField("_maxRandomHeight", serializedObject, "Max height", "The maximum random height.", parent); maxRandomHeightField.setChildLabelWidth(labelWidth); minRandomHeightField.bindMaxValueProperty("_minRandomHeight", "_maxRandomHeight", serializedObject); maxRandomHeightField.bindMinValueProperty("_maxRandomHeight", "_minRandomHeight", serializedObject); EnumField intPatternWrapModeField = UI.createEnumField(typeof(IntPatternWrapMode), "_heightPatternWrapMode", serializedObject, "Wrap mode", "The wrap mode determines how the pattern is sampled outside the bounds of its value array.", parent); intPatternWrapModeField.setChildLabelWidth(labelWidth); IMGUIContainer heightPatternContainer = UI.createIMGUIContainer(parent); heightPatternContainer.name = "_heightPatternContainer"; heightPatternContainer.onGUIHandler = () => { IntPattern selectedPattern = EditorUIEx.intPatternSelectionField("Pattern", labelWidth, _heightPattern); if (selectedPattern != _heightPattern) { UndoEx.record(this); _heightPattern = selectedPattern; EditorUtility.SetDirty(this); } }; minRandomHeightField.setDisplayVisible(heightMode == SegmentsObjectSpawnHeightMode.Random); maxRandomHeightField.setDisplayVisible(heightMode == SegmentsObjectSpawnHeightMode.Random); heightPatternContainer.setDisplayVisible(heightMode == SegmentsObjectSpawnHeightMode.Pattern); intPatternWrapModeField.setDisplayVisible(heightMode == SegmentsObjectSpawnHeightMode.Pattern); heightModeField.RegisterValueChangedCallback((p) => { minRandomHeightField.setDisplayVisible(heightMode == SegmentsObjectSpawnHeightMode.Random); maxRandomHeightField.setDisplayVisible(heightMode == SegmentsObjectSpawnHeightMode.Random); heightPatternContainer.setDisplayVisible(heightMode == SegmentsObjectSpawnHeightMode.Pattern); intPatternWrapModeField.setDisplayVisible(heightMode == SegmentsObjectSpawnHeightMode.Pattern); }); } private void createJitterModeControls(VisualElement parent, float labelWidth) { var jitterModeField = UI.createEnumField(typeof(SegmentsObjectSpawnJitterMode), "_jitterMode", serializedObject, "Jitter mode", "Allows you to specify " + "the way in which the plugin will apply random offsets to the objects' positions in a direction perpendicular to each segment.", parent); jitterModeField.setChildLabelWidth(labelWidth); var minJitterField = UI.createFloatField("_minJitter", serializedObject, "Min jitter", "Minimum jitter amount.", 0.0f, parent); minJitterField.setChildLabelWidth(labelWidth); minJitterField.bindMaxValueProperty("_minJitter", "_maxJitter", 0.0f, serializedObject); var maxJitterField = UI.createFloatField("_maxJitter", serializedObject, "Max jitter", "Maximum jitter amount.", 0.0f, parent); maxJitterField.setChildLabelWidth(labelWidth); maxJitterField.bindMinValueProperty("_maxJitter", "_minJitter", 0.0f, serializedObject); minJitterField.setDisplayVisible(jitterMode != SegmentsObjectSpawnJitterMode.None); maxJitterField.setDisplayVisible(jitterMode != SegmentsObjectSpawnJitterMode.None); var minJitterHeightField = UI.createIntegerField("_minJitterHeight", serializedObject, "Min height", "Jitter will be applied to objects in the [Min height, Max height] range.", parent); minJitterHeightField.setChildLabelWidth(labelWidth); minJitterHeightField.bindMaxValueProperty("_minJitterHeight", "_maxJitterHeight", serializedObject); var maxJitterHeightField = UI.createIntegerField("_maxJitterHeight", serializedObject, "Max height", "Jitter will be applied to objects in the [Min height, Max height] range.", parent); maxJitterHeightField.setChildLabelWidth(labelWidth); maxJitterHeightField.bindMinValueProperty("_maxJitterHeight", "_minJitterHeight", serializedObject); minJitterHeightField.setDisplayVisible(jitterMode == SegmentsObjectSpawnJitterMode.HeightRange); maxJitterHeightField.setDisplayVisible(jitterMode == SegmentsObjectSpawnJitterMode.HeightRange); jitterModeField.RegisterValueChangedCallback((p) => { minJitterField.setDisplayVisible(jitterMode != SegmentsObjectSpawnJitterMode.None); maxJitterField.setDisplayVisible(jitterMode != SegmentsObjectSpawnJitterMode.None); minJitterHeightField.setDisplayVisible(jitterMode == SegmentsObjectSpawnJitterMode.HeightRange); maxJitterHeightField.setDisplayVisible(jitterMode == SegmentsObjectSpawnJitterMode.HeightRange); }); } private void createFillModeControls(VisualElement parent, float labelWidth) { EnumField fillModeField = UI.createEnumField(typeof(SegmentsObjectSpawnFillMode), "_fillMode", serializedObject, "Fill mode", "Allows you to specify the segment fill mode.", parent); fillModeField.setChildLabelWidth(labelWidth); IntegerField beginBorderWidthField = UI.createIntegerField("_beginBorderWidth", serializedObject, "Begin width", "The border width applied at the beginning of the segment chain.", 0, parent); beginBorderWidthField.setChildLabelWidth(labelWidth); IntegerField endBorderWidthField = UI.createIntegerField("_endBorderWidth", serializedObject, "End width", "The border width applied at the end of the segment chain.", 0, parent); endBorderWidthField.setChildLabelWidth(labelWidth); IntegerField topBorderWidthField = UI.createIntegerField("_topBorderWidth", serializedObject, "Top width", "The border width applied at the top of the segments. Note: Top means the last cell in a stack. If a stack " + "grows downwards, top will be treated as the bottom most cell.", 0, parent); topBorderWidthField.setChildLabelWidth(labelWidth); IntegerField bottomBorderWidthField = UI.createIntegerField("_bottomBorderWidth", serializedObject, "Bottom width", "The border width applied at the bottom of the segments. Note: Bottom means the first cell in a stack.", 0, parent); bottomBorderWidthField.setChildLabelWidth(labelWidth); IntegerField segmentCapBorderWidthField = UI.createIntegerField("_segmentCapBorderWidth", serializedObject, "Segment cap width", "The border width applied to cap a segment when the chain reaches a dead-end.", 0, parent); segmentCapBorderWidthField.setChildLabelWidth(labelWidth); beginBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); endBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); topBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); bottomBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); segmentCapBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); fillModeField.RegisterValueChangedCallback(p => { beginBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); endBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); topBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); bottomBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); segmentCapBorderWidthField.setDisplayVisible(fillMode == SegmentsObjectSpawnFillMode.Border); }); } private void createPrefabPickModeControls(VisualElement parent, float labelWidth) { EnumField pickModeField = UI.createEnumField(typeof(SegmentsObjectSpawnPrefabPickMode), "_prefabPickMode", serializedObject, "Prefab pick mode", "Allows you to specify the prefabs that will be used to spawn objects in the segment chain.", parent); pickModeField.setChildLabelWidth(labelWidth); IMGUIContainer randomPrefabProfileContainer = UI.createIMGUIContainer(parent); randomPrefabProfileContainer.name = "_randomPrefabProfileContainer"; randomPrefabProfileContainer.onGUIHandler = () => { string newName = EditorUIEx.profileNameSelectionField (RandomPrefabProfileDb.instance, "Random prefab profile", labelWidth, _randomPrefabProfileName); if (newName != _randomPrefabProfileName) { UndoEx.record(this); _randomPrefabProfileName = newName; EditorUtility.SetDirty(this); } GUI.enabled = true; }; IMGUIContainer intRangePrefabProfileContainer = UI.createIMGUIContainer(parent); intRangePrefabProfileContainer.name = "_intRangePrefabProfileContainer"; intRangePrefabProfileContainer.onGUIHandler = () => { string newName = EditorUIEx.profileNameSelectionField (IntRangePrefabProfileDb.instance, "Int range prefab profile", labelWidth, _heightRangePrefabProfileName); if (newName != _heightRangePrefabProfileName) { UndoEx.record(this); _heightRangePrefabProfileName = newName; EditorUtility.SetDirty(this); } GUI.enabled = true; }; randomPrefabProfileContainer.setDisplayVisible(prefabPickMode == SegmentsObjectSpawnPrefabPickMode.Random); intRangePrefabProfileContainer.setDisplayVisible(prefabPickMode == SegmentsObjectSpawnPrefabPickMode.HeightRange); pickModeField.RegisterValueChangedCallback(p => { randomPrefabProfileContainer.setDisplayVisible(prefabPickMode == SegmentsObjectSpawnPrefabPickMode.Random); intRangePrefabProfileContainer.setDisplayVisible(prefabPickMode == SegmentsObjectSpawnPrefabPickMode.HeightRange); }); } private void createProjectionModeControls(VisualElement parent, float labelWidth) { VisualElement ctrl = UI.createEnumField(typeof(SegmentsObjectSpawnProjectionMode), "_projectionMode", serializedObject, "Projection mode", "Allows you to specify how the spawned objects will be projected in the scene.", parent); ctrl.setChildLabelWidth(labelWidth); } } } #endif