Beatmap Sections & Latency Reduction (#170)

* prep UI for chart section

* all special layers now on one area

todo: have buttons toggle between special layers  (selection mode shows all?), use the tabs system for this

* swapping between special timelines - prelim

* special entities can be placed

* spec. timeline base functions complete

music volume changes should work now

* attempt at input lag reduction

needs testing

* fix dsp issues

* smaller DSP buffer?

* Revert "smaller DSP buffer?"

This reverts commit 9d36db5ff90cf4e2d7bb8db9b4b7376cb493e02b.

* make conductor clock use real time (double)

change order of execution of input-related scripts to further attempt a reduction in input latency

* start values can be changed

make the old special entity bar visible when the corresponding type is selected

* creation of Chart Sections (TODO: GO REFERENCE)

* added GO references

* section edit dialog

* disable wrapping on chart section obj

* backspace can now delete entities

* entities don't shift when duplicated

* fix PlayerActionEvent order of operations

- fixed remix loading trying to clear special timeline while it's writing to itself

* make oop check match parity

* more operation order fix

* fix Karate Man BG initialization

* show section progress in editor

todo: section progress in-game

* more fix for entity duping
This commit is contained in:
minenice55 2022-09-18 16:48:14 -04:00 committed by GitHub
parent 8df4a11666
commit d74fe11e68
51 changed files with 5944 additions and 1129 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,108 @@
fileFormatVersion: 2
guid: e85d5d286a8191b499c570d33dd0899c
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -0,0 +1,108 @@
fileFormatVersion: 2
guid: dd516f1a3380ca642939d4fa86603249
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -31,6 +31,8 @@ namespace HeavenStudio
// Current time of the song
private float time;
double lastAbsTime;
// an AudioSource attached to this GameObject that will play the music.
public AudioSource musicSource;
@ -140,6 +142,7 @@ namespace HeavenStudio
musicSource.PlayScheduled(AudioSettings.dspTime);
}
}
lastAbsTime = Time.realtimeSinceStartupAsDouble;
// GameManager.instance.SetCurrentEventToClosest(songPositionInBeats);
}
@ -172,7 +175,9 @@ namespace HeavenStudio
if (isPlaying)
{
var dt = Time.unscaledDeltaTime * musicSource.pitch;
double absTime = Time.realtimeSinceStartupAsDouble;
float dt = (float) (absTime - lastAbsTime) * musicSource.pitch;
lastAbsTime = absTime;
time += dt;
@ -344,7 +349,7 @@ namespace HeavenStudio
secPerBeat = 60f / songBpm;
}
public void SetVolume(int percent)
public void SetVolume(float percent)
{
musicSource.volume = percent / 100f;
}

View file

@ -31,19 +31,28 @@ namespace HeavenStudio
Coroutine currentGameSwitchIE;
[Header("Properties")]
public int currentEvent, currentTempoEvent, currentPreEvent, currentPreSwitch;
public int currentEvent, currentTempoEvent, currentVolumeEvent, currentSectionEvent,
currentPreEvent, currentPreSwitch;
public float endBeat;
public float startOffset;
public bool playOnStart;
public float startBeat;
[NonSerialized] public GameObject currentGameO;
public bool autoplay;
public bool canInput = true;
public DynamicBeatmap.ChartSection currentSection, nextSection;
public float sectionProgress { get {
if (currentSection == null) return 0;
if (nextSection == null) return (Conductor.instance.songPositionInBeats - currentSection.beat) / (endBeat - currentSection.beat);
return (Conductor.instance.songPositionInBeats - currentSection.beat) / (nextSection.beat - currentSection.beat);
}}
public event Action<float> onBeatChanged;
public event Action<float> onBeatChanged;
public event Action<DynamicBeatmap.ChartSection> onSectionChange;
public int BeatmapEntities()
{
return Beatmap.entities.Count + Beatmap.tempoChanges.Count;
return Beatmap.entities.Count + Beatmap.tempoChanges.Count + Beatmap.volumeChanges.Count + Beatmap.beatmapSections.Count;
}
public static GameManager instance { get; private set; }
@ -219,21 +228,46 @@ namespace HeavenStudio
if (!Conductor.instance.isPlaying)
return;
List<float> entities = Beatmap.entities.Select(c => c.beat).ToList();
List<float> tempoChanges = Beatmap.tempoChanges.Select(c => c.beat).ToList();
List<float> entities = Beatmap.entities.Select(c => c.beat).ToList();
List<float> tempoChanges = Beatmap.tempoChanges.Select(c => c.beat).ToList();
if (currentTempoEvent < Beatmap.tempoChanges.Count && currentTempoEvent >= 0)
{
// Debug.Log("Checking Tempo Change at " + tempoChanges[currentTempoEvent] + ", current beat " + Conductor.instance.songPositionInBeats);
if (Conductor.instance.songPositionInBeats >= tempoChanges[currentTempoEvent])
{
// Debug.Log("Tempo Change at " + Conductor.instance.songPositionInBeats + " of bpm " + DynamicBeatmap.tempoChanges[currentTempoEvent].tempo);
Conductor.instance.SetBpm(Beatmap.tempoChanges[currentTempoEvent].tempo);
Conductor.instance.timeSinceLastTempoChange = Time.time;
currentTempoEvent++;
}
}
List<float> volumeChanges = Beatmap.volumeChanges.Select(c => c.beat).ToList();
if (currentVolumeEvent < Beatmap.volumeChanges.Count && currentVolumeEvent >= 0)
{
if (Conductor.instance.songPositionInBeats >= volumeChanges[currentVolumeEvent])
{
Conductor.instance.SetVolume(Beatmap.volumeChanges[currentVolumeEvent].volume);
currentVolumeEvent++;
}
}
List<float> chartSections = Beatmap.beatmapSections.Select(c => c.beat).ToList();
if (currentSectionEvent < Beatmap.beatmapSections.Count && currentSectionEvent >= 0)
{
if (Conductor.instance.songPositionInBeats >= chartSections[currentSectionEvent])
{
Debug.Log("Section " + Beatmap.beatmapSections[currentSectionEvent].sectionName + " started");
currentSection = Beatmap.beatmapSections[currentSectionEvent];
currentSectionEvent++;
if (currentSectionEvent < Beatmap.beatmapSections.Count)
nextSection = Beatmap.beatmapSections[currentSectionEvent];
else
nextSection = null;
onSectionChange?.Invoke(currentSection);
}
}
float seekTime = 8f;
//seek ahead to preload games that have assetbundles
SeekAheadAndPreload(Conductor.instance.songPositionInBeats, seekTime);
@ -273,6 +307,8 @@ namespace HeavenStudio
// currentEvent += gameManagerEntities.Count;
}
}
}
public void ToggleInputs(bool inputs)
@ -305,6 +341,10 @@ namespace HeavenStudio
}
KillAllSounds();
Minigame miniGame = currentGameO.GetComponent<Minigame>();
if (miniGame != null)
miniGame.OnPlay(beat);
}
public void Pause()
@ -389,10 +429,17 @@ namespace HeavenStudio
{
SetGame(newGame);
}
List<DynamicBeatmap.DynamicEntity> allEnds = EventCaller.GetAllInGameManagerList("gameManager", new string[] { "end" });
if (allEnds.Count > 0)
endBeat = allEnds.Select(c => c.beat).Min();
else
endBeat = Conductor.instance.SongLengthInBeats();
}
else
{
SetGame("noGame");
endBeat = Conductor.instance.SongLengthInBeats();
}
if (Beatmap.tempoChanges.Count > 0)
@ -413,6 +460,39 @@ namespace HeavenStudio
// Debug.Log("currentTempoEvent is now " + currentTempoEvent);
}
if (Beatmap.volumeChanges.Count > 0)
{
currentVolumeEvent = 0;
List<float> volumeChanges = Beatmap.volumeChanges.Select(c => c.beat).ToList();
for (int t = 0; t < volumeChanges.Count; t++)
{
if (volumeChanges[t] > beat)
{
break;
}
currentVolumeEvent = t;
}
}
currentSection = null;
nextSection = null;
if (Beatmap.beatmapSections.Count > 0)
{
currentSectionEvent = 0;
List<float> beatmapSections = Beatmap.beatmapSections.Select(c => c.beat).ToList();
for (int t = 0; t < beatmapSections.Count; t++)
{
if (beatmapSections[t] > beat)
{
break;
}
currentSectionEvent = t;
}
}
onSectionChange?.Invoke(currentSection);
SeekAheadAndPreload(beat);
}

View file

@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -43
executionOrder: -44
icon: {instanceID: 0}
userData:
assetBundleName:

View file

@ -135,6 +135,7 @@ namespace HeavenStudio.Games.Scripts_FanClub
float yWeight = -(yMul*yMul) + 1f;
motionRoot.transform.localPosition = new Vector3(0, 3f * yWeight);
shadow.transform.localScale = new Vector3((1f-yWeight*0.8f) * 1.4f, (1f-yWeight*0.8f) * 1.4f, 1f);
animator.Play("FanJump", -1, 0);
}
else
{

View file

@ -446,8 +446,24 @@ namespace HeavenStudio.Games
cameraPosition = CameraPosition[0].position;
}
public override void OnPlay(float beat)
{
var cond = Conductor.instance;
if (!cond.isPlaying)
{
SetBgEffectsToLast(beat);
// remove all children of the ItemHolder
foreach (Transform child in ItemHolder)
{
Destroy(child.gameObject);
}
}
}
private void Start()
{
var cond = Conductor.instance;
GameCamera.additionalPosition = cameraPosition - GameCamera.defaultPosition;
bgEffectAnimator = BGEffect.GetComponent<Animator>();
bgEffectSpriteRenderer = BGEffect.GetComponent<SpriteRenderer>();
@ -456,7 +472,8 @@ namespace HeavenStudio.Games
bgBloodRenderer = BGBlood.GetComponent<SpriteRenderer>();
bgRadialRenderer = BGRadial.GetComponent<SpriteRenderer>();
SetBgAndShadowCol(WantBgChangeStart, WantBgChangeLength, bgType, (int) currentShadowType, BackgroundColors[bgType], customShadowColour, (int)currentBgEffect);
SetBgEffectsToLast(cond.songPositionInBeats);
SetBgAndShadowCol(WantBgChangeStart, WantBgChangeLength, bgType, (int) currentShadowType, bgColour, customShadowColour, (int)currentBgEffect);
SetBgTexture(textureType, textureFilterType, filterColour, filterColour);
UpdateMaterialColour(BodyColor, HighlightColor, ItemColor);
ToggleBop(WantBop);
@ -806,10 +823,10 @@ namespace HeavenStudio.Games
var e = bgfx[i];
if (e.beat > beat)
break;
SetBgAndShadowCol(e.beat, e.length, e["type"], e["type2"], e["colorA"], e["colorB"], e["type3"]);
SetBgTexture(e["type4"], e["type5"], e["colorC"], e["colorD"]);
SetBgEffectsUnloaded(e.beat, e.length, e["type"], e["type2"], e["colorA"], e["colorB"], e["type3"], e["type4"], e["type5"], e["colorC"], e["colorD"]);
}
var camfx = GameManager.instance.Beatmap.entities.FindAll(en => en.datamodel == "karateman/special camera");
DoSpecialCamera(0, 0, true);
for (int i = 0; i < camfx.Count; i++)
{
var e = camfx[i];
@ -817,17 +834,16 @@ namespace HeavenStudio.Games
break;
DoSpecialCamera(e.beat, e.length, e["toggle"]);
}
// has issues when creating a new hitx entity so this is deactivated for now
// var hitx = GameManager.instance.Beatmap.entities.FindAll(en => en.datamodel == "karateman/hitX");
// for (int i = 0; i < hitx.Count; i++)
// {
// var e = hitx[i];
// if (e.beat > beat)
// break;
// Debug.Log("hitx");
// DoWord(e.beat, e["type"], false);
// }
var objfx = GameManager.instance.Beatmap.entities.FindAll(en => en.datamodel == "karateman/set object colors");
for (int i = 0; i < objfx.Count; i++)
{
var e = objfx[i];
if (e.beat > beat)
break;
UpdateMaterialColour(e["colorA"], e["colorB"], e["colorC"]);
}
SetBgAndShadowCol(WantBgChangeStart, WantBgChangeLength, bgType, (int) currentShadowType, bgColour, customShadowColour, (int)currentBgEffect);
SetBgTexture(textureType, textureFilterType, filterColour, filterColour);
}
public static void SetBgEffectsUnloaded(float beat, float length, int newBgType, int newShadowType, Color bgCol, Color shadowCol, int bgFx, int texture, int textureFilter, Color filterCol, Color filterColNext)

View file

@ -6,7 +6,7 @@ namespace HeavenStudio.Games
{
public class Minigame : MonoBehaviour
{
public static float earlyTime = 0.1f, perfectTime = 0.08f, aceEarlyTime = 0.02f, aceLateTime = 0.02f, lateTime = 0.08f, endTime = 0.1f;
public static float earlyTime = 0.1f, perfectTime = 0.08f, aceEarlyTime = 0.025f, aceLateTime = 0.025f, lateTime = 0.08f, endTime = 0.1f;
public List<Minigame.Eligible> EligibleHits = new List<Minigame.Eligible>();
[System.Serializable]
@ -132,7 +132,6 @@ namespace HeavenStudio.Games
{
PlayerActionEvent input = GetClosestScheduledInput();
if (input == null) return false;
return input.IsExpectingInputNow();
}
@ -190,6 +189,11 @@ namespace HeavenStudio.Games
}
public virtual void OnPlay(float beat)
{
}
public int MultipleEventsAtOnce()
{
int sameTime = 0;

View file

@ -52,6 +52,7 @@ namespace HeavenStudio.Games
this.canHit = canHit;
}
public void Update()
{
if(!Conductor.instance.NotStopped()){CleanUp();} // If the song is stopped entirely in the editor, destroy itself as we don't want duplicates

View file

@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
executionOrder: 5
icon: {instanceID: 0}
userData:
assetBundleName:

View file

@ -59,6 +59,7 @@ namespace HeavenStudio
DontDestroyOnLoad(this.gameObject);
instance = this;
Starpelly.OS.ChangeWindowTitle("Heaven Studio DEMO");
QualitySettings.maxQueuedFrames = 1;
PlayerInput.InitInputControllers();
}

View file

@ -64,7 +64,7 @@ namespace HeavenStudio.Editor.Commands
{
Pos p = new Pos();
p.eventObj = eventObjs[i];
p.lastPos_ = eventObjs[i].lastPos_;
p.lastPos_ = eventObjs[i].moveStartPos;
p.previousPos = eventObjs[i].transform.localPosition;
this.pos.Add(p);
}

View file

@ -134,7 +134,7 @@ namespace HeavenStudio.Editor
Fullscreen();
}
if (Input.GetKeyDown(KeyCode.Delete))
if (Input.GetKeyDown(KeyCode.Delete) || Input.GetKeyDown(KeyCode.Backspace))
{
List<TimelineEventObj> ev = new List<TimelineEventObj>();
for (int i = 0; i < Selections.instance.eventsSelected.Count; i++) ev.Add(Selections.instance.eventsSelected[i]);
@ -409,9 +409,9 @@ namespace HeavenStudio.Editor
{
GameManager.instance.LoadRemix(json, type);
Timeline.instance.LoadRemix();
Timeline.instance.TempoInfo.UpdateStartingBPMText();
Timeline.instance.VolumeInfo.UpdateStartingVolumeText();
Timeline.instance.TempoInfo.UpdateOffsetText();
// Timeline.instance.SpecialInfo.UpdateStartingBPMText();
// Timeline.instance.VolumeInfo.UpdateStartingVolumeText();
// Timeline.instance.SpecialInfo.UpdateOffsetText();
Timeline.FitToSong();
currentRemixPath = string.Empty;

View file

@ -19,8 +19,10 @@ namespace HeavenStudio.Editor
[Header("Components")]
[SerializeField] private Image layer;
[SerializeField] private Image specialLayers;
[SerializeField] private Image tempoLayer;
[SerializeField] private Image musicLayer;
[SerializeField] private Image sectionLayer;
private void Awake()
{
@ -29,10 +31,14 @@ namespace HeavenStudio.Editor
private void Start()
{
specialLayers.GetComponent<Image>().color = theme.properties.SpecialLayersCol.Hex2RGB();
tempoLayer.GetComponent<Image>().color = theme.properties.TempoLayerCol.Hex2RGB();
musicLayer.GetComponent<Image>().color = theme.properties.MusicLayerCol.Hex2RGB();
sectionLayer.GetComponent<Image>().color = theme.properties.SectionLayerCol.Hex2RGB();
Tooltip.AddTooltip(specialLayers.gameObject, $"All Special Tracks");
Tooltip.AddTooltip(tempoLayer.gameObject, $"Tempo Track");
Tooltip.AddTooltip(musicLayer.gameObject, $"Music Volume Track");
Tooltip.AddTooltip(sectionLayer.gameObject, $"Remix Sections Track");
layer.gameObject.SetActive(false);

View file

@ -183,10 +183,11 @@ namespace HeavenStudio.Editor
public void Drag()
{
if (Conductor.instance.NotStopped() || !Timeline.instance.timelineState.selected) return;
if (Conductor.instance.NotStopped() || Editor.instance.inAuthorativeMenu) return;
if (Timeline.instance.CheckIfMouseInTimeline() && dragTimes < 1)
{
Timeline.instance.timelineState.SetState(Timeline.CurrentTimelineState.State.Selection);
dragTimes++;
TimelineEventObj eventObj;

View file

@ -12,8 +12,10 @@ namespace HeavenStudio.Editor
[Serializable]
public class Properties
{
public string SpecialLayersCol;
public string TempoLayerCol;
public string MusicLayerCol;
public string SectionLayerCol;
public string Layer1Col;
public string Layer2Col;

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a7de3a0880c755a48a30d4e4f740c68c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,51 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio;
using HeavenStudio.Editor;
using HeavenStudio.Editor.Track;
using TMPro;
public class SectionDialog : Dialog
{
SectionTimelineObj sectionObj;
[SerializeField] TMP_InputField sectionName;
public void SwitchSectionDialog()
{
if(dialog.activeSelf) {
sectionObj = null;
dialog.SetActive(false);
Editor.instance.inAuthorativeMenu = false;
} else {
Editor.instance.inAuthorativeMenu = true;
ResetAllDialogs();
dialog.SetActive(true);
}
}
public void SetSectionObj(SectionTimelineObj sectionObj)
{
this.sectionObj = sectionObj;
sectionName.text = sectionObj.chartSection.sectionName;
}
public void DeleteSection()
{
if(dialog.activeSelf) {
dialog.SetActive(false);
Editor.instance.inAuthorativeMenu = false;
}
if (sectionObj == null) return;
GameManager.instance.Beatmap.beatmapSections.Remove(sectionObj.chartSection);
sectionObj.DeleteObj();
}
public void ChangeSectionName(string name)
{
if (sectionObj == null) return;
sectionObj.chartSection.sectionName = name;
sectionObj.UpdateLabel();
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ea7831ec549a9984c8c3e5afd98bac2f
guid: 7e5d39fb5bc171f44ba013cf8e37fdd2
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -0,0 +1,229 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using TMPro;
using Starpelly;
namespace HeavenStudio.Editor.Track
{
public class SpecialTimeline : MonoBehaviour
{
[Header("References")]
[SerializeField] private RectTransform RefTempoChange;
[SerializeField] private RectTransform RefVolumeChange;
[SerializeField] private RectTransform RefSectionChange;
[Header("Components")]
private RectTransform rectTransform;
public List<SpecialTimelineObj> specialTimelineObjs = new List<SpecialTimelineObj>();
[System.Flags]
public enum HoveringTypes
{
TempoChange = 1,
VolumeChange = 2,
SectionChange = 4,
}
public static HoveringTypes hoveringTypes = 0;
private bool firstUpdate;
public static SpecialTimeline instance;
private void Start()
{
instance = this;
rectTransform = this.GetComponent<RectTransform>();
Setup();
}
public void Setup()
{
ClearSpecialTimeline();
foreach (var tempoChange in GameManager.instance.Beatmap.tempoChanges)
AddTempoChange(false, tempoChange);
foreach (var volumeChange in GameManager.instance.Beatmap.volumeChanges)
AddVolumeChange(false, volumeChange);
foreach (var sectionChange in GameManager.instance.Beatmap.beatmapSections)
AddChartSection(false, sectionChange);
Timeline.instance.timelineState.SetState(Timeline.CurrentTimelineState.State.Selection);
FixObjectsVisibility();
}
private void Update()
{
if (!firstUpdate)
{
hoveringTypes = 0;
firstUpdate = true;
}
if (Timeline.instance.userIsEditingInputField || Editor.instance.inAuthorativeMenu)
return;
if (!Conductor.instance.NotStopped())
{
if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Input.mousePosition, Editor.instance.EditorCamera))
{
if (Input.GetMouseButtonDown(0))
{
switch (Timeline.instance.timelineState.currentState)
{
case Timeline.CurrentTimelineState.State.TempoChange:
if (!hoveringTypes.HasFlag(HoveringTypes.TempoChange))
AddTempoChange(true);
break;
case Timeline.CurrentTimelineState.State.MusicVolume:
if (!hoveringTypes.HasFlag(HoveringTypes.VolumeChange))
AddVolumeChange(true);
break;
case Timeline.CurrentTimelineState.State.ChartSection:
if (!hoveringTypes.HasFlag(HoveringTypes.SectionChange))
AddChartSection(true);
break;
}
}
}
}
hoveringTypes = 0;
}
public void FixObjectsVisibility()
{
foreach (SpecialTimelineObj obj in specialTimelineObjs)
{
obj.SetVisibility(Timeline.instance.timelineState.currentState);
}
}
public void ClearSpecialTimeline()
{
foreach (SpecialTimelineObj obj in specialTimelineObjs)
{
Destroy(obj.gameObject);
}
specialTimelineObjs.Clear();
}
public void AddTempoChange(bool create, DynamicBeatmap.TempoChange tempoChange_ = null)
{
GameObject tempoChange = Instantiate(RefTempoChange.gameObject, this.transform);
tempoChange.transform.GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.TempoLayerCol.Hex2RGB();
tempoChange.transform.GetChild(1).GetComponent<Image>().color = EditorTheme.theme.properties.TempoLayerCol.Hex2RGB();
tempoChange.transform.GetChild(2).GetComponent<TMP_Text>().color = EditorTheme.theme.properties.TempoLayerCol.Hex2RGB();
tempoChange.SetActive(true);
TempoTimelineObj tempoTimelineObj = tempoChange.GetComponent<TempoTimelineObj>();
if (create == true)
{
tempoChange.transform.position = new Vector3(Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition).x + 0.08f, tempoChange.transform.position.y);
tempoChange.transform.localPosition = new Vector3(Starpelly.Mathp.Round2Nearest(tempoChange.transform.localPosition.x, Timeline.SnapInterval()), tempoChange.transform.localPosition.y);
DynamicBeatmap.TempoChange tempoC = new DynamicBeatmap.TempoChange();
tempoC.beat = tempoChange.transform.localPosition.x;
tempoC.tempo = GameManager.instance.Beatmap.bpm;
tempoTimelineObj.tempoChange = tempoC;
GameManager.instance.Beatmap.tempoChanges.Add(tempoC);
}
else
{
tempoChange.transform.localPosition = new Vector3(tempoChange_.beat, tempoChange.transform.localPosition.y);
tempoTimelineObj.tempoChange = tempoChange_;
}
tempoTimelineObj.SetVisibility(Timeline.instance.timelineState.currentState);
specialTimelineObjs.Add(tempoTimelineObj);
Timeline.instance.FitToSong();
}
public void AddVolumeChange(bool create, DynamicBeatmap.VolumeChange volumeChange_ = null)
{
GameObject volumeChange = Instantiate(RefVolumeChange.gameObject, this.transform);
volumeChange.transform.GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.MusicLayerCol.Hex2RGB();
volumeChange.transform.GetChild(1).GetComponent<Image>().color = EditorTheme.theme.properties.MusicLayerCol.Hex2RGB();
volumeChange.transform.GetChild(2).GetComponent<TMP_Text>().color = EditorTheme.theme.properties.MusicLayerCol.Hex2RGB();
volumeChange.SetActive(true);
VolumeTimelineObj volumeTimelineObj = volumeChange.GetComponent<VolumeTimelineObj>();
if (create == true)
{
volumeChange.transform.position = new Vector3(Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition).x + 0.08f, volumeChange.transform.position.y);
volumeChange.transform.localPosition = new Vector3(Starpelly.Mathp.Round2Nearest(volumeChange.transform.localPosition.x, Timeline.SnapInterval()), volumeChange.transform.localPosition.y);
DynamicBeatmap.VolumeChange volumeC = new DynamicBeatmap.VolumeChange();
volumeC.beat = volumeChange.transform.localPosition.x;
volumeC.volume = GameManager.instance.Beatmap.musicVolume;
volumeTimelineObj.volumeChange = volumeC;
GameManager.instance.Beatmap.volumeChanges.Add(volumeC);
}
else
{
volumeChange.transform.localPosition = new Vector3(volumeChange_.beat, volumeChange.transform.localPosition.y);
volumeTimelineObj.volumeChange = volumeChange_;
}
volumeTimelineObj.SetVisibility(Timeline.instance.timelineState.currentState);
specialTimelineObjs.Add(volumeTimelineObj);
}
public void AddChartSection(bool create, DynamicBeatmap.ChartSection chartSection_ = null)
{
GameObject chartSection = Instantiate(RefSectionChange.gameObject, this.transform);
chartSection.transform.GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.SectionLayerCol.Hex2RGB();
chartSection.transform.GetChild(1).GetComponent<Image>().color = EditorTheme.theme.properties.SectionLayerCol.Hex2RGB();
chartSection.transform.GetChild(2).GetComponent<Image>().color = EditorTheme.theme.properties.SectionLayerCol.Hex2RGB();
chartSection.transform.GetChild(3).GetComponent<TMP_Text>().color = EditorTheme.theme.properties.SectionLayerCol.Hex2RGB();
chartSection.SetActive(true);
SectionTimelineObj sectionTimelineObj = chartSection.GetComponent<SectionTimelineObj>();
if (create == true)
{
chartSection.transform.position = new Vector3(Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition).x + 0.08f, chartSection.transform.position.y);
chartSection.transform.localPosition = new Vector3(Starpelly.Mathp.Round2Nearest(chartSection.transform.localPosition.x, Timeline.SnapInterval()), chartSection.transform.localPosition.y);
DynamicBeatmap.ChartSection sectionC = new DynamicBeatmap.ChartSection();
sectionC.beat = chartSection.transform.localPosition.x;
sectionC.sectionName = "New Section";
sectionC.startPerfect = false;
sectionC.isCheckpoint = false;
sectionTimelineObj.chartSection = sectionC;
GameManager.instance.Beatmap.beatmapSections.Add(sectionC);
}
else
{
chartSection.transform.localPosition = new Vector3(chartSection_.beat, chartSection.transform.localPosition.y);
sectionTimelineObj.chartSection = chartSection_;
}
sectionTimelineObj.SetVisibility(Timeline.instance.timelineState.currentState);
specialTimelineObjs.Add(sectionTimelineObj);
//auto-open the dialog
sectionTimelineObj.OnRightClick();
}
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 10dd19278a802c24fbeb39d1ccb23219
guid: 364cfb513d7ef744cb0d4828804188e0
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 46f4e0c7199fe9648bcc8cc5c601cdf3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Editor.Track;
namespace HeavenStudio.Editor
{
public class SpecialTimelineAll : TabsContent
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public override void OnOpenTab()
{
SpecialTimeline.instance.FixObjectsVisibility();
}
public override void OnCloseTab()
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e15bb84f43093e94d8360fa51074bb97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Editor.Track;
namespace HeavenStudio.Editor
{
public class SpecialTimelineSection : TabsContent
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public override void OnOpenTab()
{
SpecialTimeline.instance.FixObjectsVisibility();
}
public override void OnCloseTab()
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e528ff67df36f6242bd525e4b3911f4e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Editor.Track;
namespace HeavenStudio.Editor
{
public class SpecialTimelineTempo : TabsContent
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public override void OnOpenTab()
{
SpecialTimeline.instance.FixObjectsVisibility();
}
public override void OnCloseTab()
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b802d26536208b4b9ca9994187788a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Editor.Track;
namespace HeavenStudio.Editor
{
public class SpecialTimelineVolume : TabsContent
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public override void OnOpenTab()
{
SpecialTimeline.instance.FixObjectsVisibility();
}
public override void OnCloseTab()
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 01f0c8cfacd823a40a2f3cc7d01ac78a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c80527f878ac1594bb0eedc6884a3a5f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,92 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
namespace HeavenStudio.Editor.Track
{
public class SectionTimelineObj : SpecialTimelineObj
{
[Header("Components")]
[SerializeField] private TMP_Text sectionLabel;
[SerializeField] private GameObject chartLine;
[SerializeField] private SectionDialog sectionDialog;
public DynamicBeatmap.ChartSection chartSection;
new private void Update()
{
base.Update();
if (hovering)
{
SpecialTimeline.hoveringTypes |= SpecialTimeline.HoveringTypes.SectionChange;
}
UpdateLabel();
}
public void UpdateLabel()
{
sectionLabel.text = chartSection.sectionName;
}
public override void Init()
{
UpdateLabel();
}
public override void OnLeftClick()
{
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.ChartSection)
StartMove();
}
public override void OnRightClick()
{
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.ChartSection)
{
sectionDialog.SetSectionObj(this);
sectionDialog.SwitchSectionDialog();
}
}
public override bool OnMove(float beat)
{
foreach (var sectionChange in GameManager.instance.Beatmap.beatmapSections)
{
if (this.chartSection == sectionChange)
continue;
if (beat > sectionChange.beat - Timeline.instance.snapInterval && beat < sectionChange.beat + Timeline.instance.snapInterval)
return false;
}
this.chartSection.beat = beat;
return true;
}
public override void SetVisibility(Timeline.CurrentTimelineState.State state)
{
if (state == Timeline.CurrentTimelineState.State.ChartSection || state == Timeline.CurrentTimelineState.State.Selection)
{
gameObject.SetActive(true);
if (state == Timeline.CurrentTimelineState.State.ChartSection)
{
chartLine.SetActive(true);
sectionLabel.gameObject.SetActive(true);
}
else
{
chartLine.SetActive(false);
sectionLabel.gameObject.SetActive(false);
}
}
else
{
gameObject.SetActive(false);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 396d5b0b822f8da4cb7b855a39b4a90f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,103 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
namespace HeavenStudio.Editor.Track
{
public class SpecialTimelineObj : MonoBehaviour
{
[Header("Components")]
[SerializeField] private RectTransform rectTransform;
[SerializeField] private RectTransform raycastRect;
private float startPosX;
private bool moving = false;
public bool hovering;
private float lastPosX;
private void Start()
{
rectTransform = GetComponent<RectTransform>();
}
protected void Update()
{
if (!Conductor.instance.NotStopped())
{
if (RectTransformUtility.RectangleContainsScreenPoint(raycastRect, Input.mousePosition, Editor.instance.EditorCamera))
{
if (Input.GetMouseButtonDown(0))
{
OnLeftClick();
}
else if (Input.GetMouseButtonDown(1))
{
OnRightClick();
}
hovering = true;
}
else
{
hovering = false;
}
if (moving)
{
Vector3 mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
transform.position = new Vector3(mousePos.x - startPosX, transform.position.y, 0);
transform.localPosition = new Vector3(Mathf.Clamp(Starpelly.Mathp.Round2Nearest(transform.localPosition.x, Timeline.SnapInterval()), 0, Mathf.Infinity), transform.localPosition.y);
if (Input.GetMouseButtonUp(0))
{
if (!OnMove(transform.localPosition.x))
transform.localPosition = new Vector3(lastPosX, transform.localPosition.y);
moving = false;
lastPosX = transform.localPosition.x;
}
}
}
else
{
if (moving)
{
if (!OnMove(transform.localPosition.x))
transform.localPosition = new Vector3(lastPosX, transform.localPosition.y);
moving = false;
lastPosX = transform.localPosition.x;
}
hovering = false;
}
}
public void StartMove()
{
Vector3 mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
startPosX = mousePos.x - transform.position.x;
moving = true;
lastPosX = transform.localPosition.x;
}
public void DeleteObj()
{
transform.parent.GetComponent<SpecialTimeline>().specialTimelineObjs.Remove(this);
Destroy(this.gameObject);
}
//events
public virtual void Init() {}
public virtual void OnLeftClick() {}
public virtual void OnRightClick() {}
public virtual bool OnMove(float beat)
{
return true;
}
public virtual void SetVisibility(Timeline.CurrentTimelineState.State state) {}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4dda06181c616dc4bb406f3d5f3bb6cf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,98 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
namespace HeavenStudio.Editor.Track
{
public class TempoTimelineObj : SpecialTimelineObj
{
[Header("Components")]
[SerializeField] private TMP_Text tempoTXT;
[SerializeField] private GameObject tempoLine;
public DynamicBeatmap.TempoChange tempoChange;
new private void Update()
{
base.Update();
if (hovering)
{
SpecialTimeline.hoveringTypes |= SpecialTimeline.HoveringTypes.TempoChange;
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.TempoChange)
{
float newTempo = Input.mouseScrollDelta.y;
if (Input.GetKey(KeyCode.LeftShift))
newTempo *= 5f;
if (Input.GetKey(KeyCode.LeftControl))
newTempo /= 100f;
tempoChange.tempo += newTempo;
//make sure tempo is positive
if (tempoChange.tempo < 1)
tempoChange.tempo = 1;
}
}
UpdateTempo();
}
private void UpdateTempo()
{
tempoTXT.text = $"{tempoChange.tempo} BPM";
Timeline.instance.FitToSong();
}
public override void Init()
{
UpdateTempo();
}
public override void OnLeftClick()
{
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.TempoChange)
StartMove();
}
public override void OnRightClick()
{
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.TempoChange)
{
GameManager.instance.Beatmap.tempoChanges.Remove(tempoChange);
DeleteObj();
}
}
public override bool OnMove(float beat)
{
foreach (var tempoChange in GameManager.instance.Beatmap.tempoChanges)
{
if (this.tempoChange == tempoChange)
continue;
if (beat > tempoChange.beat - Timeline.instance.snapInterval && beat < tempoChange.beat + Timeline.instance.snapInterval)
return false;
}
this.tempoChange.beat = beat;
return true;
}
public override void SetVisibility(Timeline.CurrentTimelineState.State state)
{
if (state == Timeline.CurrentTimelineState.State.TempoChange || state == Timeline.CurrentTimelineState.State.Selection)
{
gameObject.SetActive(true);
if (state == Timeline.CurrentTimelineState.State.TempoChange)
tempoLine.SetActive(true);
else
tempoLine.SetActive(false);
}
else
gameObject.SetActive(false);
}
}
}

View file

@ -0,0 +1,96 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
namespace HeavenStudio.Editor.Track
{
public class VolumeTimelineObj : SpecialTimelineObj
{
[Header("Components")]
[SerializeField] private TMP_Text volumeTXT;
[SerializeField] private GameObject volumeLine;
public DynamicBeatmap.VolumeChange volumeChange;
new private void Update()
{
base.Update();
if (hovering)
{
SpecialTimeline.hoveringTypes |= SpecialTimeline.HoveringTypes.VolumeChange;
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.MusicVolume)
{
float newVolume = Input.mouseScrollDelta.y;
if (Input.GetKey(KeyCode.LeftShift))
newVolume *= 5f;
if (Input.GetKey(KeyCode.LeftControl))
newVolume /= 100f;
volumeChange.volume += newVolume;
//make sure volume is positive
volumeChange.volume = Mathf.Clamp(volumeChange.volume, 0, 100);
}
}
UpdateVolume();
}
private void UpdateVolume()
{
volumeTXT.text = $"{volumeChange.volume}%";
}
public override void Init()
{
UpdateVolume();
}
public override void OnLeftClick()
{
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.MusicVolume)
StartMove();
}
public override void OnRightClick()
{
if (Timeline.instance.timelineState.currentState == Timeline.CurrentTimelineState.State.MusicVolume)
{
GameManager.instance.Beatmap.volumeChanges.Remove(volumeChange);
DeleteObj();
}
}
public override bool OnMove(float beat)
{
foreach (var volumeChange in GameManager.instance.Beatmap.volumeChanges)
{
if (this.volumeChange == volumeChange)
continue;
if (beat > volumeChange.beat - Timeline.instance.snapInterval && beat < volumeChange.beat + Timeline.instance.snapInterval)
return false;
}
this.volumeChange.beat = beat;
return true;
}
public override void SetVisibility(Timeline.CurrentTimelineState.State state)
{
if (state == Timeline.CurrentTimelineState.State.MusicVolume || state == Timeline.CurrentTimelineState.State.Selection)
{
gameObject.SetActive(true);
if (state == Timeline.CurrentTimelineState.State.MusicVolume)
volumeLine.SetActive(true);
else
volumeLine.SetActive(false);
}
else
gameObject.SetActive(false);
}
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 86bb8f2f290876a4387f1ea6fedf332b
guid: 84c1633846a16fb42baa226572335fae
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -1,180 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using TMPro;
using Starpelly;
namespace HeavenStudio.Editor.Track
{
public class TempoTimeline : MonoBehaviour
{
[Header("Components")]
private RectTransform rectTransform;
[SerializeField] private RectTransform RefTempoChange;
public TMP_InputField StartingBPM;
private RectTransform StartingBPMRect;
public TMP_InputField FirstBeatOffset;
public List<TempoTimelineObj> tempoTimelineObjs = new List<TempoTimelineObj>();
private bool firstUpdate;
private void Start()
{
rectTransform = this.GetComponent<RectTransform>();
StartingBPMRect = StartingBPM.GetComponent<RectTransform>();
for (int i = 0; i < GameManager.instance.Beatmap.tempoChanges.Count; i++)
{
DynamicBeatmap.TempoChange tempoChange = GameManager.instance.Beatmap.tempoChanges[i];
AddTempoChange(false, tempoChange);
}
}
private void Update()
{
if (!firstUpdate)
{
UpdateStartingBPMText();
UpdateOffsetText();
firstUpdate = true;
}
if (Timeline.instance.userIsEditingInputField)
return;
if (Timeline.instance.timelineState.tempoChange && !Conductor.instance.NotStopped())
{
if (RectTransformUtility.RectangleContainsScreenPoint(rectTransform, Input.mousePosition, Editor.instance.EditorCamera))
{
if (Input.GetMouseButtonDown(0))
{
if (tempoTimelineObjs.FindAll(c => c.hovering == true).Count == 0)
{
AddTempoChange(true);
}
}
}
if (RectTransformUtility.RectangleContainsScreenPoint(StartingBPMRect, Input.mousePosition, Editor.instance.EditorCamera))
{
float increase = Input.mouseScrollDelta.y;
if (Input.GetKey(KeyCode.LeftControl))
increase /= 100f;
if (Input.GetKey(KeyCode.LeftShift))
increase *= 5f;
if (increase != 0f)
{
GameManager.instance.Beatmap.bpm += increase;
UpdateStartingBPMText();
UpdateStartingBPMFromText(); // In case the scrolled-to value is invalid.
}
}
}
}
public void UpdateStartingBPMText()
{
StartingBPM.text = GameManager.instance.Beatmap.bpm.ToString("G");
}
public void UpdateOffsetText()
{
FirstBeatOffset.text = (GameManager.instance.Beatmap.firstBeatOffset * 1000f).ToString("G");
}
public void UpdateStartingBPMFromText()
{
// Failsafe against empty string.
if (String.IsNullOrEmpty(StartingBPM.text))
StartingBPM.text = "120";
var newBPM = Convert.ToSingle(StartingBPM.text);
// Failsafe against negative BPM.
if (newBPM < 1f)
{
StartingBPM.text = "1";
newBPM = 1;
}
// Limit decimal places to 4.
newBPM = (float)System.Math.Round(newBPM, 4);
GameManager.instance.Beatmap.bpm = newBPM;
// In case the newBPM ended up differing from the inputted string.
UpdateStartingBPMText();
Timeline.instance.FitToSong();
}
public void UpdateOffsetFromText()
{
// Failsafe against empty string.
if (String.IsNullOrEmpty(FirstBeatOffset.text))
FirstBeatOffset.text = "0";
// Convert ms to s.
var newOffset = Convert.ToSingle(FirstBeatOffset.text) / 1000f;
// Limit decimal places to 4.
newOffset = (float)System.Math.Round(newOffset, 4);
GameManager.instance.Beatmap.firstBeatOffset = newOffset;
UpdateOffsetText();
}
public void ClearTempoTimeline()
{
foreach (TempoTimelineObj tempoTimelineObj in tempoTimelineObjs)
{
Destroy(tempoTimelineObj.gameObject);
}
tempoTimelineObjs.Clear();
}
public void AddTempoChange(bool create, DynamicBeatmap.TempoChange tempoChange_ = null)
{
GameObject tempoChange = Instantiate(RefTempoChange.gameObject, this.transform);
tempoChange.transform.GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.TempoLayerCol.Hex2RGB();
tempoChange.transform.GetChild(1).GetComponent<Image>().color = EditorTheme.theme.properties.TempoLayerCol.Hex2RGB();
tempoChange.transform.GetChild(2).GetComponent<TMP_Text>().color = EditorTheme.theme.properties.TempoLayerCol.Hex2RGB();
tempoChange.SetActive(true);
TempoTimelineObj tempoTimelineObj = tempoChange.GetComponent<TempoTimelineObj>();
if (create == true)
{
tempoChange.transform.position = new Vector3(Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition).x + 0.08f, tempoChange.transform.position.y);
tempoChange.transform.localPosition = new Vector3(Starpelly.Mathp.Round2Nearest(tempoChange.transform.localPosition.x, Timeline.SnapInterval()), tempoChange.transform.localPosition.y);
DynamicBeatmap.TempoChange tempoC = new DynamicBeatmap.TempoChange();
tempoC.beat = tempoChange.transform.localPosition.x;
tempoC.tempo = GameManager.instance.Beatmap.bpm;
tempoTimelineObj.tempoChange = tempoC;
GameManager.instance.Beatmap.tempoChanges.Add(tempoC);
}
else
{
tempoChange.transform.localPosition = new Vector3(tempoChange_.beat, tempoChange.transform.localPosition.y);
tempoTimelineObj.tempoChange = tempoChange_;
}
tempoTimelineObjs.Add(tempoTimelineObj);
Timeline.instance.FitToSong();
}
}
}

View file

@ -1,106 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
namespace HeavenStudio.Editor.Track
{
public class TempoTimelineObj : MonoBehaviour
{
[Header("Components")]
[SerializeField] private RectTransform rectTransform;
[SerializeField] private TMP_Text tempoTXT;
[SerializeField] private RectTransform raycastRect;
public DynamicBeatmap.TempoChange tempoChange;
private float startPosX;
private bool moving = false;
public bool hovering;
private float lastPosX;
private void Start()
{
rectTransform = GetComponent<RectTransform>();
tempoTXT = transform.GetChild(2).GetComponent<TMP_Text>();
UpdateTempo();
}
private void Update()
{
if (Timeline.instance.timelineState.tempoChange && !Conductor.instance.NotStopped())
{
if (RectTransformUtility.RectangleContainsScreenPoint(raycastRect, Input.mousePosition, Editor.instance.EditorCamera))
{
float newTempo = Input.mouseScrollDelta.y;
if (Input.GetKey(KeyCode.LeftShift))
newTempo *= 5f;
if (Input.GetKey(KeyCode.LeftControl))
newTempo /= 100f;
tempoChange.tempo += newTempo;
//make sure tempo is positive
if (tempoChange.tempo < 1)
tempoChange.tempo = 1;
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
startPosX = mousePos.x - transform.position.x;
moving = true;
lastPosX = transform.localPosition.x;
}
else if (Input.GetMouseButtonDown(1))
{
GameManager.instance.Beatmap.tempoChanges.Remove(tempoChange);
transform.parent.GetComponent<TempoTimeline>().tempoTimelineObjs.Remove(this);
Destroy(this.gameObject);
}
hovering = true;
}
else
{
hovering = false;
}
if (moving)
{
Vector3 mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
transform.position = new Vector3(mousePos.x - startPosX, transform.position.y, 0);
transform.localPosition = new Vector3(Mathf.Clamp(Starpelly.Mathp.Round2Nearest(transform.localPosition.x, Timeline.SnapInterval()), 0, Mathf.Infinity), transform.localPosition.y);
}
if (Input.GetMouseButtonUp(0))
{
if (transform.parent.GetComponent<TempoTimeline>().tempoTimelineObjs.Find(c => c.gameObject.transform.localPosition.x == this.transform.localPosition.x && c != this) != null)
{
transform.localPosition = new Vector3(lastPosX, transform.localPosition.y);
}
else
{
tempoChange.beat = transform.localPosition.x;
}
moving = false;
lastPosX = transform.localPosition.x;
}
UpdateTempo();
}
}
private void UpdateTempo()
{
tempoTXT.text = $"{tempoChange.tempo} BPM";
Timeline.instance.FitToSong();
}
}
}

View file

@ -1,4 +1,4 @@
using System.Collections;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
@ -34,45 +34,109 @@ namespace HeavenStudio.Editor.Track
public class CurrentTimelineState
{
public bool selected;
public bool tempoChange;
public bool musicVolume;
public enum State
{
Selection,
TempoChange,
MusicVolume,
ChartSection
}
public State currentState = State.Selection;
public bool selected { get { return currentState == State.Selection; } }
public bool tempoChange { get { return currentState == State.TempoChange; } }
public bool musicVolume { get { return currentState == State.MusicVolume; } }
public bool chartSection { get { return currentState == State.ChartSection; } }
public void SetState(bool selected, bool tempoChange, bool musicVolume)
{
if (Conductor.instance.NotStopped()) return;
this.selected = selected;
this.tempoChange = tempoChange;
this.musicVolume = musicVolume;
if (selected)
{
currentState = State.Selection;
instance.SelectionsBTN.transform.GetChild(0).GetComponent<Image>().color = Color.white;
instance.SelectionsBTN.GetComponent<TabButton>().Invoke("OnClick", 0);
}
else
instance.SelectionsBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
if (tempoChange)
{
currentState = State.TempoChange;
instance.TempoChangeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.white;
instance.TempoChangeBTN.GetComponent<TabButton>().Invoke("OnClick", 0);
}
else
instance.TempoChangeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
if (musicVolume)
{
currentState = State.MusicVolume;
instance.MusicVolumeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.white;
instance.MusicVolumeBTN.GetComponent<TabButton>().Invoke("OnClick", 0);
}
else
instance.MusicVolumeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
}
public void SetState(State state)
{
if (Conductor.instance.NotStopped()) return;
currentState = state;
if (selected)
{
instance.SelectionsBTN.transform.GetChild(0).GetComponent<Image>().color = Color.white;
instance.SelectionsBTN.GetComponent<TabButton>().Invoke("OnClick", 0);
}
else
instance.SelectionsBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
if (tempoChange)
{
instance.TempoChangeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.white;
instance.TempoChangeBTN.GetComponent<TabButton>().Invoke("OnClick", 0);
}
else
instance.TempoChangeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
if (musicVolume)
{
instance.MusicVolumeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.white;
instance.MusicVolumeBTN.GetComponent<TabButton>().Invoke("OnClick", 0);
}
else
instance.MusicVolumeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
if (chartSection)
{
instance.ChartSectionBTN.transform.GetChild(0).GetComponent<Image>().color = Color.white;
instance.ChartSectionBTN.GetComponent<TabButton>().Invoke("OnClick", 0);
}
else
instance.ChartSectionBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
}
}
[Header("Timeline Components")]
[SerializeField] private RectTransform TimelineSlider;
[SerializeField] private RectTransform TimelineGridSelect;
[SerializeField] private RectTransform TimelineEventGrid;
[SerializeField] private TMP_Text TimelinePlaybackBeat;
public RectTransform TimelineContent;
[SerializeField] private RectTransform TimelineSongPosLineRef;
[SerializeField] private RectTransform TimelineEventObjRef;
[SerializeField] private RectTransform LayersRect;
public TempoTimeline TempoInfo;
public VolumeTimeline VolumeInfo;
[SerializeField] private GameObject TimelineSectionDisplay;
[SerializeField] private TMP_Text TimelineSectionText;
[SerializeField] private Slider TimelineSectionProgress;
[Header("Timeline Inputs")]
public TMP_InputField FirstBeatOffset;
public TMP_InputField StartingTempoSpecialAll;
public TMP_InputField StartingTempoSpecialTempo;
public TMP_InputField StartingVolumeSpecialVolume;
public SpecialTimeline SpecialInfo;
private RectTransform TimelineSongPosLine;
[Header("Timeline Playbar")]
@ -84,6 +148,7 @@ namespace HeavenStudio.Editor.Track
public Button SelectionsBTN;
public Button TempoChangeBTN;
public Button MusicVolumeBTN;
public Button ChartSectionBTN;
public Slider PlaybackSpeed;
public Vector3[] LayerCorners = new Vector3[4];
@ -117,16 +182,10 @@ namespace HeavenStudio.Editor.Track
AddEventObject(e.datamodel, false, new Vector3(e.beat, -e.track * LayerHeight()), e, false, RandomID());
}
//tempo changes
TempoInfo.ClearTempoTimeline();
for (int i = 0; i < GameManager.instance.Beatmap.tempoChanges.Count; i++)
{
var t = GameManager.instance.Beatmap.tempoChanges[i];
TempoInfo.AddTempoChange(false, t);
}
//volume changes
SpecialInfo.Setup();
UpdateOffsetText();
UpdateStartingBPMText();
UpdateStartingVolText();
}
public void Init()
@ -170,15 +229,19 @@ namespace HeavenStudio.Editor.Track
SelectionsBTN.onClick.AddListener(delegate
{
timelineState.SetState(true, false, false);
timelineState.SetState(CurrentTimelineState.State.Selection);
});
TempoChangeBTN.onClick.AddListener(delegate
{
timelineState.SetState(false, true, false);
timelineState.SetState(CurrentTimelineState.State.TempoChange);
});
MusicVolumeBTN.onClick.AddListener(delegate
{
timelineState.SetState(false, false, true);
timelineState.SetState(CurrentTimelineState.State.MusicVolume);
});
ChartSectionBTN.onClick.AddListener(delegate
{
timelineState.SetState(CurrentTimelineState.State.ChartSection);
});
Tooltip.AddTooltip(SongBeat.gameObject, "Current Beat");
@ -195,15 +258,21 @@ namespace HeavenStudio.Editor.Track
Tooltip.AddTooltip(SelectionsBTN.gameObject, "Tool: Selection <color=#adadad>[1]</color>");
Tooltip.AddTooltip(TempoChangeBTN.gameObject, "Tool: Tempo Change <color=#adadad>[2]</color>");
Tooltip.AddTooltip(MusicVolumeBTN.gameObject, "Tool: Music Volume <color=#adadad>[3]</color>");
Tooltip.AddTooltip(ChartSectionBTN.gameObject, "Tool: Beatmap Sections <color=#adadad>[4]</color>");
Tooltip.AddTooltip(StartingTempoSpecialAll.gameObject, "Starting Tempo (BPM)");
Tooltip.AddTooltip(StartingTempoSpecialTempo.gameObject, "Starting Tempo (BPM)");
Tooltip.AddTooltip(StartingVolumeSpecialVolume.gameObject, "Starting Volume (%)");
Tooltip.AddTooltip(PlaybackSpeed.gameObject, "The preview's playback speed. Right click to reset to 1.0");
SetTimeButtonColors(true, false, false);
MetronomeBTN.transform.GetChild(0).GetComponent<Image>().color = Color.gray;
timelineState.SetState(true, false, false);
timelineState.SetState(CurrentTimelineState.State.Selection);
AutoBtnUpdate();
GameManager.instance.onSectionChange += OnSectionChange;
}
public void FitToSong()
@ -269,6 +338,7 @@ namespace HeavenStudio.Editor.Track
SongBeat.text = $"Beat {string.Format("{0:0.000}", Conductor.instance.songPositionInBeats)}";
SongPos.text = FormatTime(Conductor.instance.songPosition);
}
TimelineSectionProgress.value = GameManager.instance.sectionProgress;
SliderControl();
@ -300,15 +370,19 @@ namespace HeavenStudio.Editor.Track
if (Input.GetKeyDown(KeyCode.Alpha1))
{
timelineState.SetState(true, false, false);
timelineState.SetState(CurrentTimelineState.State.Selection);
}
else if (Input.GetKeyDown(KeyCode.Alpha2))
{
timelineState.SetState(false, true, false);
timelineState.SetState(CurrentTimelineState.State.TempoChange);
}
else if (Input.GetKeyDown(KeyCode.Alpha3))
{
timelineState.SetState(false, false, true);
timelineState.SetState(CurrentTimelineState.State.MusicVolume);
}
else if (Input.GetKeyDown(KeyCode.Alpha4))
{
timelineState.SetState(CurrentTimelineState.State.ChartSection);
}
@ -350,7 +424,7 @@ namespace HeavenStudio.Editor.Track
TimelineContent.transform.localPosition = new Vector3(Mathf.Clamp(TimelineContent.transform.localPosition.x, Mathf.NegativeInfinity, 0), TimelineContent.transform.localPosition.y);
CurrentTempo.text = $" = {Conductor.instance.songBpm}";
CurrentTempo.text = $" = {Conductor.instance.songBpm}";
LayersRect.GetWorldCorners(LayerCorners);
}
@ -497,7 +571,7 @@ namespace HeavenStudio.Editor.Track
public bool CheckIfMouseInTimeline()
{
return (this.gameObject.activeSelf && RectTransformUtility.RectangleContainsScreenPoint(TimelineContent.transform.parent.gameObject.GetComponent<RectTransform>(), Input.mousePosition, Editor.instance.EditorCamera));
return (this.gameObject.activeSelf && RectTransformUtility.RectangleContainsScreenPoint(TimelineEventGrid, Input.mousePosition, Editor.instance.EditorCamera));
}
#endregion
@ -683,6 +757,95 @@ namespace HeavenStudio.Editor.Track
}
}
public void UpdateOffsetText()
{
FirstBeatOffset.text = (GameManager.instance.Beatmap.firstBeatOffset * 1000f).ToString("G");
}
public void UpdateOffsetFromText()
{
// Failsafe against empty string.
if (String.IsNullOrEmpty(FirstBeatOffset.text))
FirstBeatOffset.text = "0";
// Convert ms to s.
var newOffset = Convert.ToSingle(FirstBeatOffset.text) / 1000f;
// Limit decimal places to 4.
newOffset = (float)System.Math.Round(newOffset, 4);
GameManager.instance.Beatmap.firstBeatOffset = newOffset;
UpdateOffsetText();
}
public void UpdateStartingBPMText()
{
StartingTempoSpecialAll.text = GameManager.instance.Beatmap.bpm.ToString("G");
StartingTempoSpecialTempo.text = StartingTempoSpecialAll.text;
}
public void UpdateStartingBPMFromText(bool all)
{
string text = all ? StartingTempoSpecialAll.text : StartingTempoSpecialTempo.text;
// Failsafe against empty string.
if (String.IsNullOrEmpty(text))
text = "120";
var newBPM = Convert.ToDouble(text);
// Failsafe against negative BPM.
if (newBPM < 1f)
{
text = "1";
newBPM = 1;
}
// Limit decimal places to 4.
newBPM = System.Math.Round(newBPM, 4);
GameManager.instance.Beatmap.bpm = (float) newBPM;
// In case the newBPM ended up differing from the inputted string.
UpdateStartingBPMText();
Timeline.instance.FitToSong();
}
public void UpdateStartingVolText()
{
StartingVolumeSpecialVolume.text = (GameManager.instance.Beatmap.musicVolume).ToString("G");
}
public void UpdateStartingVolFromText()
{
// Failsafe against empty string.
if (String.IsNullOrEmpty(StartingVolumeSpecialVolume.text))
StartingVolumeSpecialVolume.text = "100";
var newVol = Convert.ToInt32(StartingVolumeSpecialVolume.text);
newVol = Mathf.Clamp(newVol, 0, 100);
GameManager.instance.Beatmap.musicVolume = newVol;
UpdateStartingVolText();
}
public void OnSectionChange(DynamicBeatmap.ChartSection section)
{
if (section == null)
{
TimelineSectionDisplay.SetActive(false);
}
else
{
if (!TimelineSectionDisplay.activeSelf)
TimelineSectionDisplay.SetActive(true);
TimelineSectionText.text = section.sectionName;
TimelineSectionProgress.value = GameManager.instance.sectionProgress;
}
}
#endregion
#region Commands

View file

@ -14,7 +14,7 @@ namespace HeavenStudio.Editor.Track
private float startPosY;
private Vector3 lastPos;
public Vector2 lastPos_;
public Vector2 moveStartPos;
private RectTransform rectTransform;
[Header("Components")]
@ -50,7 +50,7 @@ namespace HeavenStudio.Editor.Track
private void Start()
{
lastPos_ = transform.localPosition;
moveStartPos = transform.localPosition;
rectTransform = GetComponent<RectTransform>();
@ -163,13 +163,16 @@ namespace HeavenStudio.Editor.Track
this.wasDuplicated = false;
this.moving = false;
transform.localPosition = moveStartPos;
OnComplete(false);
var te = Timeline.instance.CopyEventObject(this);
Selections.instance.DragSelect(te);
te.wasDuplicated = true;
te.transform.localPosition = transform.localPosition;
te.lastPos_ = transform.localPosition;
te.moveStartPos = transform.localPosition;
for (int i = 0; i < Timeline.instance.eventObjs.Count; i++)
{
@ -179,12 +182,11 @@ namespace HeavenStudio.Editor.Track
te.moving = true;
}
lastPos_ = transform.localPosition;
this.transform.position = new Vector3(mousePos.x - startPosX, mousePos.y - startPosY - 0.40f, 0);
this.transform.localPosition = new Vector3(Mathf.Max(Mathp.Round2Nearest(this.transform.localPosition.x, Timeline.SnapInterval()), 0), Timeline.instance.SnapToLayer(this.transform.localPosition.y));
else
{
this.transform.position = new Vector3(mousePos.x - startPosX, mousePos.y - startPosY - 0.40f, 0);
this.transform.localPosition = new Vector3(Mathf.Max(Mathp.Round2Nearest(this.transform.localPosition.x, Timeline.SnapInterval()), 0), Timeline.instance.SnapToLayer(this.transform.localPosition.y));
}
if (lastPos != transform.localPosition)
{
@ -281,7 +283,7 @@ namespace HeavenStudio.Editor.Track
{
if (selected && Timeline.instance.timelineState.selected)
{
lastPos_ = transform.localPosition;
moveStartPos = transform.localPosition;
for (int i = 0; i < Timeline.instance.eventObjs.Count; i++)
{
@ -314,6 +316,7 @@ namespace HeavenStudio.Editor.Track
if (eligibleToMove)
{
OnComplete(true);
moveStartPos = transform.localPosition;
}
moving = false;

View file

@ -1,89 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
using TMPro;
using Starpelly;
namespace HeavenStudio.Editor.Track
{
public class VolumeTimeline : MonoBehaviour
{
[Header("Components")]
private RectTransform rectTransform;
public TMP_InputField StartingVolume;
private RectTransform StartingVolumeRect;
public List<VolumeTimelineObj> volumeTimelineObjs = new List<VolumeTimelineObj>();
private bool firstUpdate;
void Start()
{
rectTransform = this.GetComponent<RectTransform>();
StartingVolumeRect = StartingVolume.GetComponent<RectTransform>();
}
void Update()
{
if (!firstUpdate)
{
UpdateStartingVolumeText();
firstUpdate = true;
}
if (Timeline.instance.userIsEditingInputField)
return;
if (Timeline.instance.timelineState.musicVolume && !Conductor.instance.NotStopped())
{
if (RectTransformUtility.RectangleContainsScreenPoint(StartingVolumeRect, Input.mousePosition, Editor.instance.EditorCamera))
{
int increase = Mathf.RoundToInt(Input.mouseScrollDelta.y);
if (Input.GetKey(KeyCode.LeftShift))
increase *= 5;
if (increase != 0)
{
GameManager.instance.Beatmap.musicVolume += increase;
UpdateStartingVolumeText();
UpdateStartingVolumeFromText(); // In case the scrolled-to value is invalid.
}
}
}
}
public void UpdateStartingVolumeText()
{
StartingVolume.text = GameManager.instance.Beatmap.musicVolume.ToString();
}
public void UpdateStartingVolumeFromText()
{
// Failsafe against empty string.
if (String.IsNullOrEmpty(StartingVolume.text))
StartingVolume.text = "100";
var newVol = Convert.ToInt32(StartingVolume.text);
// Failsafe against invalid volume.
if (newVol > 100)
{
StartingVolume.text = "100";
newVol = 100;
}
else if (newVol < 0)
{
StartingVolume.text = "0";
newVol = 0;
}
GameManager.instance.Beatmap.musicVolume = newVol;
// In case the newVol ended up differing from the inputted string.
UpdateStartingVolumeText();
}
}
}

View file

@ -1,105 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using DG.Tweening;
namespace HeavenStudio.Editor.Track
{
public class VolumeTimelineObj : MonoBehaviour
{
[Header("Components")]
[SerializeField] private RectTransform rectTransform;
[SerializeField] private TMP_Text volumeTXT;
[SerializeField] private RectTransform raycastRect;
public DynamicBeatmap.VolumeChange volumeChange;
private float startPosX;
private bool moving = false;
public bool hovering;
private float lastPosX;
private void Start()
{
rectTransform = GetComponent<RectTransform>();
volumeTXT = transform.GetChild(2).GetComponent<TMP_Text>();
UpdateVolume();
}
private void Update()
{
if (Timeline.instance.timelineState.musicVolume && !Conductor.instance.NotStopped())
{
if (RectTransformUtility.RectangleContainsScreenPoint(raycastRect, Input.mousePosition, Editor.instance.EditorCamera))
{
float newVolume = Input.mouseScrollDelta.y;
if (Input.GetKey(KeyCode.LeftShift))
newVolume *= 5f;
if (Input.GetKey(KeyCode.LeftControl))
newVolume /= 100f;
volumeChange.volume += newVolume;
//make sure volume is positive
volumeChange.volume = Mathf.Clamp(volumeChange.volume, 0, 100);
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
startPosX = mousePos.x - transform.position.x;
moving = true;
lastPosX = transform.localPosition.x;
}
else if (Input.GetMouseButtonDown(1))
{
GameManager.instance.Beatmap.volumeChanges.Remove(volumeChange);
transform.parent.GetComponent<VolumeTimeline>().volumeTimelineObjs.Remove(this);
Destroy(this.gameObject);
}
hovering = true;
}
else
{
hovering = false;
}
if (moving)
{
Vector3 mousePos = Editor.instance.EditorCamera.ScreenToWorldPoint(Input.mousePosition);
transform.position = new Vector3(mousePos.x - startPosX, transform.position.y, 0);
transform.localPosition = new Vector3(Mathf.Clamp(Starpelly.Mathp.Round2Nearest(transform.localPosition.x, Timeline.SnapInterval()), 0, Mathf.Infinity), transform.localPosition.y);
}
if (Input.GetMouseButtonUp(0))
{
if (transform.parent.GetComponent<VolumeTimeline>().volumeTimelineObjs.Find(c => c.gameObject.transform.localPosition.x == this.transform.localPosition.x && c != this) != null)
{
transform.localPosition = new Vector3(lastPosX, transform.localPosition.y);
}
else
{
volumeChange.beat = transform.localPosition.x;
}
moving = false;
lastPosX = transform.localPosition.x;
}
UpdateVolume();
}
}
private void UpdateVolume()
{
volumeTXT.text = $"{volumeChange.volume}%";
Timeline.instance.FitToSong();
}
}
}

View file

@ -5,8 +5,11 @@
"name": "Heaven Studio Default Editor Theme",
"properties": {
"SpecialLayersCol": "f06d60",
"TempoLayerCol": "6cbcc4",
"MusicLayerCol": "a663cc",
"SectionLayerCol": "ed9b2f",
//A7F085
"Layer1Col": "ef476f",
"Layer2Col": "f5813d",

View file

@ -8,8 +8,8 @@ AudioManager:
Rolloff Scale: 1
Doppler Factor: 1
Default Speaker Mode: 2
m_SampleRate: 96000
m_DSPBufferSize: 1024
m_SampleRate: 48000
m_DSPBufferSize: 512
m_VirtualVoiceCount: 512
m_RealVoiceCount: 32
m_EnableOutputSuspension: 1
@ -17,4 +17,4 @@ AudioManager:
m_AmbisonicDecoderPlugin:
m_DisableAudio: 0
m_VirtualizeEffects: 1
m_RequestedDSPBufferSize: 0
m_RequestedDSPBufferSize: 512

View file

@ -320,7 +320,9 @@ PlayerSettings:
Android: 1
iPhone: 1
tvOS: 1
m_BuildTargetGroupLightmapEncodingQuality: []
m_BuildTargetGroupLightmapEncodingQuality:
- m_BuildTarget: Standalone
m_EncodingQuality: 1
m_BuildTargetGroupLightmapSettings: []
m_BuildTargetNormalMapEncoding: []
playModeTestRunnerEnabled: 0