diff --git a/Assets/Resources/Sprites/Editor/UI/Animations/Autoplay/Idle.anim b/Assets/Resources/Sprites/Editor/UI/Animations/Autoplay/Idle.anim index f2750ea2..61756227 100644 --- a/Assets/Resources/Sprites/Editor/UI/Animations/Autoplay/Idle.anim +++ b/Assets/Resources/Sprites/Editor/UI/Animations/Autoplay/Idle.anim @@ -16,7 +16,26 @@ AnimationClip: m_EulerCurves: [] m_PositionCurves: [] m_ScaleCurves: [] - m_FloatCurves: [] + m_FloatCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Graphic + classID: 224 + script: {fileID: 0} m_PPtrCurves: - curve: - time: 0 @@ -39,6 +58,13 @@ AnimationClip: typeID: 114 customType: 0 isPPtrCurve: 1 + - serializedVersion: 2 + path: 3003628726 + attribute: 538195251 + script: {fileID: 0} + typeID: 224 + customType: 28 + isPPtrCurve: 0 pptrCurveMapping: - {fileID: -1983818443, guid: 655fc978fc6e6ca41a3d3104b43298bd, type: 3} m_AnimationClipSettings: @@ -61,7 +87,26 @@ AnimationClip: m_KeepOriginalPositionXZ: 0 m_HeightFromFeet: 0 m_Mirror: 0 - m_EditorCurves: [] + m_EditorCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_AnchoredPosition.y + path: Graphic + classID: 224 + script: {fileID: 0} m_EulerEditorCurves: [] m_HasGenericRootTransform: 0 m_HasMotionFloatCurves: 0 diff --git a/Assets/Scenes/Editor.unity b/Assets/Scenes/Editor.unity index 56de6263..973e1437 100644 --- a/Assets/Scenes/Editor.unity +++ b/Assets/Scenes/Editor.unity @@ -10135,7 +10135,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 177.66986, y: -60.01} + m_AnchoredPosition: {x: 177.66988, y: -60.01} m_SizeDelta: {x: 42, y: 42} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &449176922 @@ -24751,6 +24751,82 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1128012797} m_CullTransparentMesh: 1 +--- !u!1 &1134629697 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1134629698} + - component: {fileID: 1134629700} + - component: {fileID: 1134629699} + m_Layer: 5 + m_Name: Image + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1134629698 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1134629697} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1806429019} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1134629699 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1134629697} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: f9232c079e126cd48a7344b23eaf42a5, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1134629700 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1134629697} + m_CullTransparentMesh: 1 --- !u!1 &1144123704 GameObject: m_ObjectHideFlags: 0 @@ -37731,6 +37807,57 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1800461596} m_CullTransparentMesh: 1 +--- !u!1 &1806429018 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1806429019} + - component: {fileID: 1806429020} + m_Layer: 5 + m_Name: BlockDeleteFXTemplate + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1806429019 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1806429018} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1134629698} + m_Father: {fileID: 1838356727} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 91.4, y: 50.84} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1806429020 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1806429018} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d7f2c4dbc99f13d4eac41ff79ee2844e, type: 3} + m_Name: + m_EditorClassIdentifier: + mainImage: {fileID: 1134629699} --- !u!1 &1813644963 GameObject: m_ObjectHideFlags: 0 @@ -38026,6 +38153,7 @@ RectTransform: - {fileID: 743531236} - {fileID: 2142375787} - {fileID: 1962968340} + - {fileID: 1806429019} m_Father: {fileID: 259713290} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -38268,6 +38396,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: EntityTemplate: {fileID: 798021450} + BlockDeleteFXTemplate: {fileID: 1806429020} --- !u!1 &1863600390 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/LevelEditor/BoxSelection.cs b/Assets/Scripts/LevelEditor/BoxSelection.cs index 1a336c96..f1c4fe65 100644 --- a/Assets/Scripts/LevelEditor/BoxSelection.cs +++ b/Assets/Scripts/LevelEditor/BoxSelection.cs @@ -107,6 +107,20 @@ namespace HeavenStudio.Editor else sizeText.text = string.Empty; + // Keeps the text always in view + var sizeTextLeft = Timeline.instance.leftSide - start.x; + sizeTextLeft = Mathf.Max(sizeTextLeft, 0); + var sizeTextRight = -(Timeline.instance.rightSide - end.x); + sizeTextRight = Mathf.Max(sizeTextRight, 0); + + var sizeTextTop = Timeline.instance.topSide - start.y; + sizeTextTop = Mathf.Max(sizeTextTop, 0); + var sizeTextBottom = -(Timeline.instance.bottomSide - end.y); + sizeTextBottom = Mathf.Max(sizeTextBottom, 0); + + sizeText.rectTransform.offsetMin = new Vector2(sizeTextLeft * Timeline.instance.PixelsPerBeat, -sizeTextTop * Timeline.instance.LayerHeight()); + sizeText.rectTransform.offsetMax = new Vector2(-sizeTextRight * Timeline.instance.PixelsPerBeat, sizeTextBottom * Timeline.instance.LayerHeight()); + Select(start, end); } diff --git a/Assets/Scripts/LevelEditor/Commands/Block.cs b/Assets/Scripts/LevelEditor/Commands/Block.cs index bd56facd..9d88673a 100644 --- a/Assets/Scripts/LevelEditor/Commands/Block.cs +++ b/Assets/Scripts/LevelEditor/Commands/Block.cs @@ -37,10 +37,11 @@ namespace HeavenStudio.Editor.Commands var marker = TimelineBlockManager.Instance.EntityMarkers[entity.guid]; var clonedEntity = entity.DeepCopy(); - clonedEntity.guid = entity.guid; // We have to do this because entities (as of when I'm typing this), do not have Guids. + clonedEntity.guid = entity.guid; deletedEntities.Add(new() { riqEntity = clonedEntity, selected = marker.selected }); + TimelineBlockManager.Instance.CreateDestroyFX(entity); Selections.instance.Deselect(marker); @@ -107,15 +108,16 @@ namespace HeavenStudio.Editor.Commands { placedEntityData = createdEntity.DeepCopy(); - var marker = TimelineBlockManager.Instance.EntityMarkers[createdEntity.guid]; + if (TimelineBlockManager.Instance.EntityMarkers.ContainsKey(createdEntity.guid)) + { + var marker = TimelineBlockManager.Instance.EntityMarkers[createdEntity.guid]; + Selections.instance.Deselect(marker); - Selections.instance.Deselect(marker); + TimelineBlockManager.Instance.EntityMarkers.Remove(createdEntity.guid); + GameObject.Destroy(marker.gameObject); + } GameManager.instance.Beatmap.Entities.Remove(createdEntity); - - TimelineBlockManager.Instance.EntityMarkers.Remove(createdEntity.guid); - GameObject.Destroy(marker.gameObject); - GameManager.instance.SortEventsList(); } } diff --git a/Assets/Scripts/LevelEditor/Theme.cs b/Assets/Scripts/LevelEditor/Theme.cs index 34b1c55e..f34d47d6 100644 --- a/Assets/Scripts/LevelEditor/Theme.cs +++ b/Assets/Scripts/LevelEditor/Theme.cs @@ -1,3 +1,4 @@ +using HeavenStudio.Editor.Track; using Newtonsoft.Json; using Starpelly; using System; @@ -55,5 +56,10 @@ namespace HeavenStudio.Editor LayersGradient.colorKeys = colorKeys.ToArray(); } + + public Color LayerGradientIndex(int layer) + { + return EditorTheme.theme.LayersGradient.Evaluate(layer / (float)(Timeline.instance.LayerCount - 1)); + } } } \ No newline at end of file diff --git a/Assets/Scripts/LevelEditor/Timeline/BlockDeleteFX.cs b/Assets/Scripts/LevelEditor/Timeline/BlockDeleteFX.cs new file mode 100644 index 00000000..fa48b85f --- /dev/null +++ b/Assets/Scripts/LevelEditor/Timeline/BlockDeleteFX.cs @@ -0,0 +1,62 @@ +using HeavenStudio.Util; +using UnityEngine; +using UnityEngine.UI; +using static UnityEditor.Experimental.GraphView.GraphView; + +namespace HeavenStudio.Editor.Track +{ + public class BlockDeleteFX : MonoBehaviour + { + private RectTransform rectTransform; + + [SerializeField] + private Image mainImage; + + private bool started = false; + private float deleteTime = 0.0f; + + private double eBeat; + private float eLength; + private int eLayer; + private bool wasESelected = false; + + public void Awake() + { + rectTransform = GetComponent(); + } + + public void Create(double beat, float length, int layer, bool selected) + { + started = true; + deleteTime = Time.time; + + eBeat = beat; + eLength = length; + eLayer = layer; + wasESelected = selected; + + Destroy(this.gameObject, 0.714f); + + Update(); + } + + private void Update() + { + if (!started) return; + + rectTransform.anchoredPosition = new Vector2((float)eBeat * Timeline.instance.PixelsPerBeat, -eLayer * Timeline.instance.LayerHeight()); + rectTransform.sizeDelta = new Vector2(eLength * Timeline.instance.PixelsPerBeat, Timeline.instance.LayerHeight()); + + + // I added this because I was going to use the effect when you undo a place as well, but I didn't like it. + // var color = (wasESelected) ? Color.cyan : EditorTheme.theme.LayerGradientIndex(eLayer); + + var color = EditorTheme.theme.LayerGradientIndex(eLayer); + var norm = (Time.time - deleteTime) * 1.4f; + mainImage.color = Color.Lerp(color, new Color(color.r, color.g, color.b, 0.0f), EasingFunction.EaseOutCirc(0, 1, norm)); + + var extrudeAnim = EasingFunction.EaseOutCirc(0.0f, 8.0f, norm); + mainImage.rectTransform.sizeDelta = new Vector2(extrudeAnim, extrudeAnim); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/LevelEditor/Timeline/BlockDeleteFX.cs.meta b/Assets/Scripts/LevelEditor/Timeline/BlockDeleteFX.cs.meta new file mode 100644 index 00000000..67f2af71 --- /dev/null +++ b/Assets/Scripts/LevelEditor/Timeline/BlockDeleteFX.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7f2c4dbc99f13d4eac41ff79ee2844e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/LevelEditor/Timeline/Timeline.cs b/Assets/Scripts/LevelEditor/Timeline/Timeline.cs index 8cf32f91..5986c3db 100644 --- a/Assets/Scripts/LevelEditor/Timeline/Timeline.cs +++ b/Assets/Scripts/LevelEditor/Timeline/Timeline.cs @@ -182,9 +182,14 @@ namespace HeavenStudio.Editor.Track public Vector3[] LayerCorners = new Vector3[4]; + // Beats public float leftSide => (RealTimelineContent.anchoredPosition.x / PixelsPerBeat) * -1; public float rightSide => (TimelineScroll.viewport.rect.width / PixelsPerBeat) + leftSide; + // Layer Height + public float topSide => RealTimelineContent.anchoredPosition.y / LayerHeight(); + public float bottomSide => topSide + (TimelineScroll.viewport.rect.height / LayerHeight()); + private Vector2 lastScreenSize; public static Timeline instance { get; private set; } diff --git a/Assets/Scripts/LevelEditor/Timeline/TimelineBlockManager.cs b/Assets/Scripts/LevelEditor/Timeline/TimelineBlockManager.cs index 5b5afe74..023c9918 100644 --- a/Assets/Scripts/LevelEditor/Timeline/TimelineBlockManager.cs +++ b/Assets/Scripts/LevelEditor/Timeline/TimelineBlockManager.cs @@ -5,6 +5,7 @@ using UnityEngine.Pool; using Jukebox; using System.Linq; +using static Jukebox.Legacy.Beatmap; namespace HeavenStudio.Editor.Track { @@ -13,6 +14,7 @@ namespace HeavenStudio.Editor.Track public static TimelineBlockManager Instance { get; private set; } public TimelineEventObj EntityTemplate; + public BlockDeleteFX BlockDeleteFXTemplate; public Dictionary EntityMarkers = new(); public ObjectPool Pool { get; private set; } @@ -186,5 +188,22 @@ namespace HeavenStudio.Editor.Track { Destroy(marker.gameObject); } + + // NOTE (PELLY): This should probably be pooled in the future. + public void CreateDestroyFX(RiqEntity entity) + { + var deleteFX = Instantiate(BlockDeleteFXTemplate, BlockDeleteFXTemplate.transform.parent); + deleteFX.gameObject.SetActive(true); + + bool selected = false; + if (EntityMarkers.ContainsKey(entity.guid)) + { + if (Selections.instance.eventsSelected.Contains(EntityMarkers[entity.guid])) + { + selected = true; + } + } + deleteFX.Create(entity.beat, entity.length, (int)entity["track"], selected); + } } } \ No newline at end of file diff --git a/Assets/Scripts/LevelEditor/Timeline/TimelineEventObj.cs b/Assets/Scripts/LevelEditor/Timeline/TimelineEventObj.cs index 6065ff9c..0d669e5e 100644 --- a/Assets/Scripts/LevelEditor/Timeline/TimelineEventObj.cs +++ b/Assets/Scripts/LevelEditor/Timeline/TimelineEventObj.cs @@ -500,7 +500,7 @@ namespace HeavenStudio.Editor.Track public void SetColor(int type) { - var c = EditorTheme.theme.LayersGradient.Evaluate(type / (float)(Timeline.instance.LayerCount - 1)); + var c = EditorTheme.theme.LayerGradientIndex(type); transform.GetChild(0).GetComponent().color = c; if (resizable)