mirror of
https://github.com/RHeavenStudio/HeavenStudio.git
synced 2025-06-12 18:57:40 +02:00
Game Overlays (#280)
* add accuracy display * temp BG for show * separate overlays prefab make proper shader for star effects * aim shakiness display * implement testing skill star * fully functional skill star * separate section display from editor * fully separate chart section display from timeline * add section to overlays * fix nullreference issues * start game layout settings * add game settings script * fix nonfunctioning scoring * invert y position logic on timing bar * add perfect challenge functionality * fix section not showing up in editor add perfect challenge option * add timing display minimal mode * Update PerfectAndPractice.png * show gismo for minigame bounds in editor * add ability to disable overlays in editor * prepare medals add new timing display graphic * hide screen preview * per-axis camera control added per request * section medals basic functionality * add medal get animations * fix bug with perfect icons * visual enhancements * adjust look of timing display minmode address audio ducking issues(?) * prepare overlay lyt editor add viewport pan, rotate, scale adjust audio setting * add layout editor UI elements * dynamic overlay creation * fix default single timing disp * set up overlay settings controls * start UI events * runtime uuid for component reference * layout editor affects overlay elements * show overlay element previews while editing * advanced audio settings * fix bug in drop-down creation * fallback defaults for the new stuff * fix textbox & overlay visibility bugs
This commit is contained in:
@ -280,9 +280,11 @@ namespace HeavenStudio
|
||||
public float GetBpmAtBeat(float beat)
|
||||
{
|
||||
var chart = GameManager.instance.Beatmap;
|
||||
if (chart.tempoChanges.Count == 0)
|
||||
return chart.bpm;
|
||||
float bpm = chart.bpm;
|
||||
|
||||
foreach (DynamicBeatmap.TempoChange t in GameManager.instance.Beatmap.tempoChanges)
|
||||
foreach (DynamicBeatmap.TempoChange t in chart.tempoChanges)
|
||||
{
|
||||
if (t.beat > beat)
|
||||
{
|
||||
@ -303,7 +305,7 @@ namespace HeavenStudio
|
||||
|
||||
float lastTempoChangeBeat = 0f;
|
||||
|
||||
foreach (DynamicBeatmap.TempoChange t in GameManager.instance.Beatmap.tempoChanges)
|
||||
foreach (DynamicBeatmap.TempoChange t in chart.tempoChanges)
|
||||
{
|
||||
if (t.beat > beat)
|
||||
{
|
||||
|
@ -12,9 +12,16 @@ namespace HeavenStudio
|
||||
public static GameCamera instance { get; private set; }
|
||||
public new Camera camera;
|
||||
|
||||
public enum CameraAxis
|
||||
{
|
||||
All,
|
||||
X,
|
||||
Y,
|
||||
Z
|
||||
}
|
||||
|
||||
private List<DynamicBeatmap.DynamicEntity> positionEvents = new List<DynamicBeatmap.DynamicEntity>();
|
||||
private List<DynamicBeatmap.DynamicEntity> rotationEvents = new List<DynamicBeatmap.DynamicEntity>();
|
||||
private List<DynamicBeatmap.DynamicEntity> scaleEvents = new List<DynamicBeatmap.DynamicEntity>();
|
||||
private List<DynamicBeatmap.DynamicEntity> shakeEvents = new List<DynamicBeatmap.DynamicEntity>();
|
||||
|
||||
/**
|
||||
@ -22,25 +29,20 @@ namespace HeavenStudio
|
||||
**/
|
||||
public static Vector3 defaultPosition = new Vector3(0, 0, -10);
|
||||
public static Vector3 defaultRotEluer = new Vector3(0, 0, 0);
|
||||
public static Vector3 defaultScale = new Vector3(16, 9, 1);
|
||||
public static Vector3 defaultShake = new Vector3(0, 0, 0);
|
||||
|
||||
/**
|
||||
camera's current transformation
|
||||
TODO: stretching (the scale param) not working, will need help with this cause I don't understand Unity's camera
|
||||
**/
|
||||
private static Vector3 position;
|
||||
private static Vector3 rotEluer;
|
||||
private static Vector3 scale;
|
||||
private static Vector3 shakeResult;
|
||||
|
||||
/**
|
||||
camera's last transformation
|
||||
TODO: stretching (the scaleLast param) not working, will need help with this cause I don't understand Unity's camera
|
||||
**/
|
||||
private static Vector3 positionLast;
|
||||
private static Vector3 rotEluerLast;
|
||||
private static Vector3 scaleLast;
|
||||
private static Vector3 shakeLast;
|
||||
|
||||
/**
|
||||
@ -71,7 +73,6 @@ namespace HeavenStudio
|
||||
|
||||
positionLast = defaultPosition;
|
||||
rotEluerLast = defaultRotEluer;
|
||||
scaleLast = defaultScale;
|
||||
}
|
||||
|
||||
public void OnBeatChanged(float beat)
|
||||
@ -81,7 +82,6 @@ namespace HeavenStudio
|
||||
|
||||
positionLast = defaultPosition;
|
||||
rotEluerLast = defaultRotEluer;
|
||||
scaleLast = defaultScale;
|
||||
|
||||
// this entire thing is a mess redo it later
|
||||
//pos
|
||||
@ -97,10 +97,6 @@ namespace HeavenStudio
|
||||
|
||||
shakeEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "screen shake" });
|
||||
|
||||
|
||||
//scale (TODO)
|
||||
// scaleEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "scale camera" });
|
||||
|
||||
UpdateCameraTranslate();
|
||||
UpdateCameraRotate();
|
||||
SetShakeIntensity();
|
||||
@ -115,7 +111,6 @@ namespace HeavenStudio
|
||||
Camera cam = GetCamera();
|
||||
cam.transform.localPosition = position + additionalPosition + shakeResult;
|
||||
cam.transform.eulerAngles = rotEluer + additionalRotEluer;
|
||||
cam.transform.localScale = Vector3.Scale(scale, additionalScale);
|
||||
}
|
||||
|
||||
private void UpdateCameraTranslate()
|
||||
@ -126,14 +121,42 @@ namespace HeavenStudio
|
||||
if (prog >= 0f)
|
||||
{
|
||||
EasingFunction.Function func = EasingFunction.GetEasingFunction((EasingFunction.Ease) e["ease"]);
|
||||
float dx = func(positionLast.x, e["valA"], Mathf.Min(prog, 1f));
|
||||
float dy = func(positionLast.y, e["valB"], Mathf.Min(prog, 1f));
|
||||
float dz = func(positionLast.z, -e["valC"], Mathf.Min(prog, 1f));
|
||||
position = new Vector3(dx, dy, dz);
|
||||
switch (e["axis"])
|
||||
{
|
||||
case (int) CameraAxis.X:
|
||||
position.x = func(positionLast.x, e["valA"], Mathf.Min(prog, 1f));
|
||||
break;
|
||||
case (int) CameraAxis.Y:
|
||||
position.y = func(positionLast.y, e["valB"], Mathf.Min(prog, 1f));
|
||||
break;
|
||||
case (int) CameraAxis.Z:
|
||||
position.z = func(positionLast.z, -e["valC"], Mathf.Min(prog, 1f));
|
||||
break;
|
||||
default:
|
||||
float dx = func(positionLast.x, e["valA"], Mathf.Min(prog, 1f));
|
||||
float dy = func(positionLast.y, e["valB"], Mathf.Min(prog, 1f));
|
||||
float dz = func(positionLast.z, -e["valC"], Mathf.Min(prog, 1f));
|
||||
position = new Vector3(dx, dy, dz);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prog > 1f)
|
||||
{
|
||||
positionLast = new Vector3(e["valA"], e["valB"], -e["valC"]);
|
||||
switch (e["axis"])
|
||||
{
|
||||
case (int) CameraAxis.X:
|
||||
positionLast.x = e["valA"];
|
||||
break;
|
||||
case (int) CameraAxis.Y:
|
||||
positionLast.y = e["valB"];
|
||||
break;
|
||||
case (int) CameraAxis.Z:
|
||||
positionLast.z = -e["valC"];
|
||||
break;
|
||||
default:
|
||||
positionLast = new Vector3(e["valA"], e["valB"], -e["valC"]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,14 +169,42 @@ namespace HeavenStudio
|
||||
if (prog >= 0f)
|
||||
{
|
||||
EasingFunction.Function func = EasingFunction.GetEasingFunction((EasingFunction.Ease) e["ease"]);
|
||||
float dx = func(rotEluerLast.x, e["valA"], Mathf.Min(prog, 1f));
|
||||
float dy = func(rotEluerLast.y, e["valB"], Mathf.Min(prog, 1f));
|
||||
float dz = func(-rotEluerLast.z, e["valC"], Mathf.Min(prog, 1f));
|
||||
rotEluer = new Vector3(dx, dy, dz); //I'm stupid and forgot to negate the rotation gfd 😢
|
||||
|
||||
switch (e["axis"])
|
||||
{
|
||||
case (int) CameraAxis.X:
|
||||
rotEluer.x = func(rotEluerLast.x, e["valA"], Mathf.Min(prog, 1f));
|
||||
break;
|
||||
case (int) CameraAxis.Y:
|
||||
rotEluer.y = func(rotEluerLast.y, e["valB"], Mathf.Min(prog, 1f));
|
||||
break;
|
||||
case (int) CameraAxis.Z:
|
||||
rotEluer.z = func(rotEluerLast.z, -e["valC"], Mathf.Min(prog, 1f));
|
||||
break;
|
||||
default:
|
||||
float dx = func(rotEluerLast.x, e["valA"], Mathf.Min(prog, 1f));
|
||||
float dy = func(rotEluerLast.y, e["valB"], Mathf.Min(prog, 1f));
|
||||
float dz = func(rotEluerLast.z, -e["valC"], Mathf.Min(prog, 1f));
|
||||
rotEluer = new Vector3(dx, dy, dz); //I'm stupid and forgot to negate the rotation gfd 😢
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prog > 1f)
|
||||
{
|
||||
switch (e["axis"])
|
||||
{
|
||||
case (int) CameraAxis.X:
|
||||
rotEluerLast.x = e["valA"];
|
||||
break;
|
||||
case (int) CameraAxis.Y:
|
||||
rotEluerLast.y = e["valB"];
|
||||
break;
|
||||
case (int) CameraAxis.Z:
|
||||
rotEluerLast.z = -e["valC"];
|
||||
break;
|
||||
default:
|
||||
rotEluerLast = new Vector3(e["valA"], e["valB"], -e["valC"]);
|
||||
break;
|
||||
}
|
||||
rotEluerLast = new Vector3(e["valA"], e["valB"], -e["valC"]);
|
||||
}
|
||||
}
|
||||
@ -180,7 +231,6 @@ namespace HeavenStudio
|
||||
{
|
||||
position = defaultPosition;
|
||||
rotEluer = defaultRotEluer;
|
||||
scale = defaultScale;
|
||||
shakeResult = defaultShake;
|
||||
}
|
||||
|
||||
@ -188,7 +238,6 @@ namespace HeavenStudio
|
||||
{
|
||||
additionalPosition = new Vector3(0, 0, 0);
|
||||
additionalRotEluer = new Vector3(0, 0, 0);
|
||||
additionalScale = new Vector3(1, 1, 1);
|
||||
}
|
||||
|
||||
public static Camera GetCamera()
|
||||
|
@ -7,6 +7,7 @@ using UnityEngine;
|
||||
using Starpelly;
|
||||
using Newtonsoft.Json;
|
||||
using HeavenStudio.Games;
|
||||
using HeavenStudio.Common;
|
||||
|
||||
namespace HeavenStudio
|
||||
{
|
||||
@ -21,7 +22,7 @@ namespace HeavenStudio
|
||||
[Header("Components")]
|
||||
public string txt;
|
||||
public string ext;
|
||||
public Camera GameCamera, CursorCam, OverlayCamera;
|
||||
public Camera GameCamera, CursorCam, OverlayCamera, StaticCamera;
|
||||
public GameObject GameLetterbox;
|
||||
public CircleCursor CircleCursor;
|
||||
[HideInInspector] public GameObject GamesHolder;
|
||||
@ -44,11 +45,7 @@ namespace HeavenStudio
|
||||
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 float sectionProgress { get; private set; }
|
||||
|
||||
public event Action<float> onBeatChanged;
|
||||
public event Action<DynamicBeatmap.ChartSection> onSectionChange;
|
||||
@ -88,6 +85,7 @@ namespace HeavenStudio
|
||||
return totalPlayerAccuracy / totalInputs;
|
||||
}
|
||||
}
|
||||
bool skillStarCollected = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@ -125,8 +123,23 @@ namespace HeavenStudio
|
||||
Conductor.instance.SetVolume(Beatmap.musicVolume);
|
||||
Conductor.instance.firstBeatOffset = Beatmap.firstBeatOffset;
|
||||
|
||||
GameObject textbox = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Textbox"));
|
||||
textbox.name = "Textbox";
|
||||
// note: serialize this shit in the inspector //
|
||||
GameObject textbox = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Textbox"));
|
||||
textbox.name = "Textbox";
|
||||
|
||||
GameObject overlays = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Overlays"));
|
||||
overlays.name = "Overlays";
|
||||
|
||||
GameObject timingDisp = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Overlays/TimingAccuracy"));
|
||||
timingDisp.name = "TimingDisplay";
|
||||
|
||||
GameObject skillStarDisp = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Overlays/SkillStar"));
|
||||
skillStarDisp.name = "SkillStar";
|
||||
|
||||
GoForAPerfect.instance.Disable();
|
||||
/////
|
||||
|
||||
|
||||
if (txt != null && ext != null)
|
||||
{
|
||||
LoadRemix(txt, ext);
|
||||
@ -206,12 +219,25 @@ namespace HeavenStudio
|
||||
}
|
||||
}
|
||||
|
||||
public void ScoreInputAccuracy(double accuracy, bool late, double weight = 1)
|
||||
public void ScoreInputAccuracy(double accuracy, bool late, double time, double weight = 1, bool doDisplay = true)
|
||||
{
|
||||
totalInputs += weight;
|
||||
totalPlayerAccuracy += accuracy * weight;
|
||||
|
||||
if (accuracy < Minigame.rankOkThreshold && weight > 0)
|
||||
{
|
||||
SkillStarManager.instance.KillStar();
|
||||
}
|
||||
|
||||
if (SkillStarManager.instance.IsEligible && !skillStarCollected && accuracy >= 1f)
|
||||
{
|
||||
if (SkillStarManager.instance.DoStarJust())
|
||||
skillStarCollected = true;
|
||||
}
|
||||
|
||||
// push the hit event to the timing display
|
||||
if (doDisplay)
|
||||
TimingAccuracyDisplay.instance.MakeAccuracyVfx(time, late);
|
||||
}
|
||||
|
||||
public void SeekAheadAndPreload(double start, float seekTime = 8f)
|
||||
@ -292,7 +318,6 @@ namespace HeavenStudio
|
||||
}
|
||||
}
|
||||
|
||||
// LateUpdate works a bit better(?) but causes some bugs (like issues with bop animations).
|
||||
private void Update()
|
||||
{
|
||||
PlayerInput.UpdateInputControllers();
|
||||
@ -301,16 +326,16 @@ namespace HeavenStudio
|
||||
return;
|
||||
if (!Conductor.instance.isPlaying)
|
||||
return;
|
||||
Conductor cond = Conductor.instance;
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (Conductor.instance.songPositionInBeatsAsDouble >= tempoChanges[currentTempoEvent])
|
||||
if (cond.songPositionInBeatsAsDouble >= tempoChanges[currentTempoEvent])
|
||||
{
|
||||
Conductor.instance.SetBpm(Beatmap.tempoChanges[currentTempoEvent].tempo);
|
||||
cond.SetBpm(Beatmap.tempoChanges[currentTempoEvent].tempo);
|
||||
currentTempoEvent++;
|
||||
}
|
||||
}
|
||||
@ -318,9 +343,9 @@ namespace HeavenStudio
|
||||
List<float> volumeChanges = Beatmap.volumeChanges.Select(c => c.beat).ToList();
|
||||
if (currentVolumeEvent < Beatmap.volumeChanges.Count && currentVolumeEvent >= 0)
|
||||
{
|
||||
if (Conductor.instance.songPositionInBeatsAsDouble >= volumeChanges[currentVolumeEvent])
|
||||
if (cond.songPositionInBeatsAsDouble >= volumeChanges[currentVolumeEvent])
|
||||
{
|
||||
Conductor.instance.SetVolume(Beatmap.volumeChanges[currentVolumeEvent].volume);
|
||||
cond.SetVolume(Beatmap.volumeChanges[currentVolumeEvent].volume);
|
||||
currentVolumeEvent++;
|
||||
}
|
||||
}
|
||||
@ -328,7 +353,7 @@ namespace HeavenStudio
|
||||
List<float> chartSections = Beatmap.beatmapSections.Select(c => c.beat).ToList();
|
||||
if (currentSectionEvent < Beatmap.beatmapSections.Count && currentSectionEvent >= 0)
|
||||
{
|
||||
if (Conductor.instance.songPositionInBeatsAsDouble >= chartSections[currentSectionEvent])
|
||||
if (cond.songPositionInBeatsAsDouble >= chartSections[currentSectionEvent])
|
||||
{
|
||||
Debug.Log("Section " + Beatmap.beatmapSections[currentSectionEvent].sectionName + " started");
|
||||
currentSection = Beatmap.beatmapSections[currentSectionEvent];
|
||||
@ -343,13 +368,13 @@ namespace HeavenStudio
|
||||
|
||||
float seekTime = 8f;
|
||||
//seek ahead to preload games that have assetbundles
|
||||
SeekAheadAndPreload(Conductor.instance.songPositionInBeatsAsDouble, seekTime);
|
||||
SeekAheadAndPreload(cond.songPositionInBeatsAsDouble, seekTime);
|
||||
|
||||
SeekAheadAndDoPreEvent(Conductor.instance.songPositionInBeatsAsDouble);
|
||||
|
||||
if (currentEvent < Beatmap.entities.Count && currentEvent >= 0)
|
||||
{
|
||||
if (Conductor.instance.songPositionInBeatsAsDouble >= entities[currentEvent])
|
||||
if (cond.songPositionInBeatsAsDouble >= entities[currentEvent])
|
||||
{
|
||||
// allows for multiple events on the same beat to be executed on the same frame, so no more 1-frame delay
|
||||
var entitiesAtSameBeat = Beatmap.entities.FindAll(c => c.beat == Beatmap.entities[currentEvent].beat && !EventCaller.FXOnlyGames().Contains(EventCaller.instance.GetMinigame(c.datamodel.Split('/')[0])));
|
||||
@ -380,10 +405,26 @@ namespace HeavenStudio
|
||||
// Thank you to @shshwdr for bring this to my attention
|
||||
currentEvent++;
|
||||
}
|
||||
|
||||
// currentEvent += gameManagerEntities.Count;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSection == null)
|
||||
{
|
||||
sectionProgress = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
float currectSectionStart = (float)cond.GetSongPosFromBeat(currentSection.beat);
|
||||
|
||||
if (nextSection == null)
|
||||
sectionProgress = (cond.songPosition - currectSectionStart) / ((float)cond.GetSongPosFromBeat(endBeat) - currectSectionStart);
|
||||
else
|
||||
sectionProgress = (cond.songPosition - currectSectionStart) / ((float)cond.GetSongPosFromBeat(nextSection.beat) - currectSectionStart);
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate() {
|
||||
OverlaysManager.instance.TogleOverlaysVisibility(Editor.Editor.instance == null || Editor.Editor.instance.fullscreen || ((PersistentDataManager.gameSettings.overlaysInEditor) && (!Editor.Editor.instance.fullscreen)) || HeavenStudio.Editor.GameSettings.InPreview);
|
||||
}
|
||||
|
||||
public void ToggleInputs(bool inputs)
|
||||
@ -402,6 +443,15 @@ namespace HeavenStudio
|
||||
totalInputs = 0;
|
||||
totalPlayerAccuracy = 0;
|
||||
|
||||
TimingAccuracyDisplay.instance.ResetArrow();
|
||||
SkillStarManager.instance.Reset();
|
||||
skillStarCollected = false;
|
||||
|
||||
GoForAPerfect.instance.perfect = true;
|
||||
GoForAPerfect.instance.Disable();
|
||||
|
||||
SectionMedalsManager.instance.Reset();
|
||||
|
||||
StartCoroutine(PlayCo(beat));
|
||||
onBeatChanged?.Invoke(beat);
|
||||
}
|
||||
@ -441,6 +491,12 @@ namespace HeavenStudio
|
||||
onBeatChanged?.Invoke(beat);
|
||||
KillAllSounds();
|
||||
|
||||
// I feel like I should standardize the names
|
||||
SkillStarManager.instance.KillStar();
|
||||
TimingAccuracyDisplay.instance.StopStarFlash();
|
||||
GoForAPerfect.instance.Disable();
|
||||
SectionMedalsManager.instance.OnRemixEnd();
|
||||
|
||||
Debug.Log($"Average input offset for playthrough: {averageInputOffset}ms");
|
||||
Debug.Log($"Accuracy for playthrough: {(PlayerAccuracy * 100) : 0.00}");
|
||||
|
||||
|
@ -3,12 +3,13 @@ using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using HeavenStudio.Util;
|
||||
using HeavenStudio.Common;
|
||||
|
||||
namespace HeavenStudio.Games
|
||||
{
|
||||
public class Minigame : MonoBehaviour
|
||||
{
|
||||
public static float earlyTime = 0.07f, perfectTime = 0.04f, aceEarlyTime = 0.01f, aceLateTime = 0.01f, lateTime = 0.04f, endTime = 0.07f;
|
||||
public static double earlyTime = 0.07f, perfectTime = 0.04f, aceEarlyTime = 0.01f, aceLateTime = 0.01f, lateTime = 0.04f, endTime = 0.07f;
|
||||
public static float rankHiThreshold = 0.8f, rankOkThreshold = 0.6f;
|
||||
[SerializeField] public SoundSequence.SequenceKeyValue[] SoundSequences;
|
||||
|
||||
@ -150,37 +151,38 @@ namespace HeavenStudio.Games
|
||||
}
|
||||
|
||||
// now should fix the fast bpm problem
|
||||
public static float EarlyTime()
|
||||
public static double EarlyTime()
|
||||
{
|
||||
return 1f - ScaleTimingMargin(earlyTime);
|
||||
return 1f - earlyTime;
|
||||
}
|
||||
|
||||
public static float PerfectTime()
|
||||
public static double PerfectTime()
|
||||
{
|
||||
return 1f - ScaleTimingMargin(perfectTime);
|
||||
return 1f - perfectTime;
|
||||
}
|
||||
|
||||
public static float LateTime()
|
||||
public static double LateTime()
|
||||
{
|
||||
return 1f + ScaleTimingMargin(lateTime);
|
||||
return 1f + lateTime;
|
||||
}
|
||||
|
||||
public static float EndTime()
|
||||
public static double EndTime()
|
||||
{
|
||||
return 1f + ScaleTimingMargin(endTime);
|
||||
return 1f + endTime;
|
||||
}
|
||||
|
||||
public static float AceStartTime()
|
||||
public static double AceStartTime()
|
||||
{
|
||||
return 1f - ScaleTimingMargin(aceEarlyTime);
|
||||
return 1f - aceEarlyTime;
|
||||
}
|
||||
|
||||
public static float AceEndTime()
|
||||
public static double AceEndTime()
|
||||
{
|
||||
return 1f + ScaleTimingMargin(aceLateTime);
|
||||
return 1f + aceLateTime;
|
||||
}
|
||||
|
||||
//scales timing windows to the BPM in an ""intelligent"" manner
|
||||
// DEPRECATED: scales timing windows to the BPM in an ""intelligent"" manner
|
||||
// only left for historical reasons
|
||||
static float ScaleTimingMargin(float f)
|
||||
{
|
||||
float bpm = Conductor.instance.songBpm * Conductor.instance.musicSource.pitch;
|
||||
@ -253,7 +255,12 @@ namespace HeavenStudio.Games
|
||||
|
||||
public void ScoreMiss(double weight = 1f)
|
||||
{
|
||||
GameManager.instance.ScoreInputAccuracy(0, true, weight);
|
||||
GameManager.instance.ScoreInputAccuracy(0, true, EndTime(), weight, false);
|
||||
if (weight > 0)
|
||||
{
|
||||
GoForAPerfect.instance.Miss();
|
||||
SectionMedalsManager.instance.MakeIneligible();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy() {
|
||||
@ -262,5 +269,10 @@ namespace HeavenStudio.Games
|
||||
evt.Disable();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDrawGizmos() {
|
||||
Gizmos.color = Color.magenta;
|
||||
Gizmos.DrawWireCube(Vector3.zero, new Vector3(17.77695f, 10, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ using DG.Tweening;
|
||||
using HeavenStudio.Util;
|
||||
using Starpelly;
|
||||
|
||||
using HeavenStudio.Common;
|
||||
|
||||
namespace HeavenStudio.Games
|
||||
{
|
||||
|
||||
@ -62,6 +64,7 @@ namespace HeavenStudio.Games
|
||||
|
||||
if (noAutoplay && autoplayOnly) autoplayOnly = false;
|
||||
if (noAutoplay && triggersAutoplay){ triggersAutoplay = false; }
|
||||
if (!enabled) return;
|
||||
|
||||
double normalizedTime = GetNormalizedTime();
|
||||
double stateProg = ((normalizedTime - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2;
|
||||
@ -161,9 +164,20 @@ namespace HeavenStudio.Games
|
||||
GameManager.instance.AvgInputOffset = offset;
|
||||
OnHit(this, (float) state);
|
||||
|
||||
if (countsForAccuracy && !(noAutoplay || autoplayOnly) && isEligible)
|
||||
GameManager.instance.ScoreInputAccuracy(TimeToAccuracy(time), time > 1.0, 1.0);
|
||||
CleanUp();
|
||||
if (countsForAccuracy && !(noAutoplay || autoplayOnly) && isEligible)
|
||||
{
|
||||
GameManager.instance.ScoreInputAccuracy(TimeToAccuracy(time), time > 1.0, time);
|
||||
if (state >= 1f || state <= -1f)
|
||||
{
|
||||
GoForAPerfect.instance.Miss();
|
||||
SectionMedalsManager.instance.MakeIneligible();
|
||||
}
|
||||
else
|
||||
{
|
||||
GoForAPerfect.instance.Hit();
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
Blank();
|
||||
@ -176,7 +190,6 @@ namespace HeavenStudio.Games
|
||||
if (time >= Minigame.AceStartTime() && time <= Minigame.AceEndTime())
|
||||
{
|
||||
// Ace
|
||||
Debug.Log("Accuracy (Ace): " + 1.0);
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
@ -190,7 +203,6 @@ namespace HeavenStudio.Games
|
||||
state = 1.0 - ((time - Minigame.AceEndTime()) / (Minigame.LateTime() - Minigame.AceEndTime()));
|
||||
state *= 1.0 - Minigame.rankHiThreshold;
|
||||
state += Minigame.rankHiThreshold;
|
||||
Debug.Log("Accuracy (Late): " + state);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -198,7 +210,6 @@ namespace HeavenStudio.Games
|
||||
state = ((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime()));
|
||||
state *= 1.0 - Minigame.rankHiThreshold;
|
||||
state += Minigame.rankHiThreshold;
|
||||
Debug.Log("Accuracy (Early): " + state);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -208,14 +219,12 @@ namespace HeavenStudio.Games
|
||||
// late half of timing window
|
||||
state = 1.0 - ((time - Minigame.LateTime()) / (Minigame.EndTime() - Minigame.LateTime()));
|
||||
state *= Minigame.rankOkThreshold;
|
||||
Debug.Log("Accuracy (Late NG): " + state);
|
||||
}
|
||||
else
|
||||
{
|
||||
//early half of timing window
|
||||
state = ((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime()));
|
||||
state *= Minigame.rankOkThreshold;
|
||||
Debug.Log("Accuracy (Early NG): " + state);
|
||||
}
|
||||
}
|
||||
return state;
|
||||
@ -230,7 +239,11 @@ namespace HeavenStudio.Games
|
||||
|
||||
CleanUp();
|
||||
if (countsForAccuracy && !(noAutoplay || autoplayOnly))
|
||||
GameManager.instance.ScoreInputAccuracy(0, true, 1.0);
|
||||
{
|
||||
GameManager.instance.ScoreInputAccuracy(0, true, 2.0, 1.0, false);
|
||||
GoForAPerfect.instance.Miss();
|
||||
SectionMedalsManager.instance.MakeIneligible();
|
||||
}
|
||||
}
|
||||
|
||||
public void Blank()
|
||||
|
@ -2,6 +2,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using HeavenStudio.Editor;
|
||||
using HeavenStudio.Editor.Track;
|
||||
|
||||
namespace HeavenStudio.Games
|
||||
@ -15,7 +16,7 @@ namespace HeavenStudio.Games
|
||||
|
||||
//the variables below seem to be mostly unused (they are never used in any meaningful way)
|
||||
public int aceTimes; //always set to 0 no matter what (also, the one time it's used doesn't seem to make sense)
|
||||
public bool isEligible; //value never used for anything
|
||||
public bool isEligible = true;
|
||||
private bool autoPlayEnabledOnStart; //value never used for anything
|
||||
|
||||
public bool triggersAutoplay = true;
|
||||
@ -147,7 +148,7 @@ namespace HeavenStudio.Games
|
||||
|
||||
private void AceVisuals()
|
||||
{
|
||||
if (Timeline.instance != null)
|
||||
if (Timeline.instance != null && Editor.Editor.instance != null && !Editor.Editor.instance.fullscreen)
|
||||
{
|
||||
Timeline.instance.AutoplayBTN.GetComponent<Animator>().Play("Ace", 0, 0);
|
||||
}
|
||||
@ -165,4 +166,4 @@ namespace HeavenStudio.Games
|
||||
MakeInEligible();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,20 @@ namespace HeavenStudio
|
||||
public static int ScreenSizeIndex = 0;
|
||||
|
||||
public static float MasterVolume = 0.8f;
|
||||
public static int currentDspSize = 256;
|
||||
public static int currentSampleRate = 44100;
|
||||
public static readonly int[] DSP_BUFFER_SIZES =
|
||||
{
|
||||
128, 256, 340, 480, 512, 1024
|
||||
};
|
||||
|
||||
public static readonly int[] SAMPLE_RATES =
|
||||
{
|
||||
22050, 44100, 48000, 88200, 96000,
|
||||
};
|
||||
|
||||
public static RenderTexture GameRenderTexture;
|
||||
public static RenderTexture OverlayRenderTexture;
|
||||
|
||||
public enum Scenes : int
|
||||
{
|
||||
@ -57,6 +71,16 @@ namespace HeavenStudio
|
||||
CustomScreenHeight = PersistentDataManager.gameSettings.resolutionHeight;
|
||||
|
||||
ChangeMasterVolume(PersistentDataManager.gameSettings.masterVolume);
|
||||
|
||||
if (PersistentDataManager.gameSettings.dspSize == 0)
|
||||
PersistentDataManager.gameSettings.dspSize = 256;
|
||||
if (PersistentDataManager.gameSettings.sampleRate == 0)
|
||||
PersistentDataManager.gameSettings.sampleRate = 44100;
|
||||
currentDspSize = PersistentDataManager.gameSettings.dspSize;
|
||||
currentSampleRate = PersistentDataManager.gameSettings.sampleRate;
|
||||
|
||||
ChangeAudioSettings(currentDspSize, currentSampleRate);
|
||||
|
||||
if (PersistentDataManager.gameSettings.isFullscreen)
|
||||
{
|
||||
Screen.SetResolution(Display.main.systemWidth, Display.main.systemHeight, FullScreenMode.FullScreenWindow);
|
||||
@ -167,15 +191,39 @@ namespace HeavenStudio
|
||||
}
|
||||
}
|
||||
|
||||
public static void ResetGameRenderTexture()
|
||||
{
|
||||
GameRenderTexture.width = Screen.width;
|
||||
GameRenderTexture.height = Screen.height;
|
||||
|
||||
OverlayRenderTexture.width = Screen.width;
|
||||
OverlayRenderTexture.height = Screen.height;
|
||||
}
|
||||
|
||||
public static void ChangeMasterVolume(float value)
|
||||
{
|
||||
MasterVolume = value;
|
||||
AudioListener.volume = MasterVolume;
|
||||
}
|
||||
|
||||
public static void ChangeAudioSettings(int dspSize, int sampleRate)
|
||||
{
|
||||
// don't reset audio if no changes are done
|
||||
AudioConfiguration config = AudioSettings.GetConfiguration();
|
||||
if (dspSize == config.dspBufferSize && sampleRate == config.sampleRate) return;
|
||||
currentDspSize = dspSize;
|
||||
currentSampleRate = sampleRate;
|
||||
|
||||
config.dspBufferSize = currentDspSize;
|
||||
config.sampleRate = currentSampleRate;
|
||||
AudioSettings.Reset(config);
|
||||
|
||||
PersistentDataManager.gameSettings.dspSize = currentDspSize;
|
||||
PersistentDataManager.gameSettings.sampleRate = currentSampleRate;
|
||||
}
|
||||
|
||||
void OnApplicationQuit()
|
||||
{
|
||||
PersistentDataManager.SaveSettings();
|
||||
Debug.Log("Disconnecting JoyShocks...");
|
||||
PlayerInput.DisconnectJoyshocks();
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using HeavenStudio.Util;
|
||||
|
||||
namespace HeavenStudio
|
||||
{
|
||||
public class GoForAPerfect : MonoBehaviour
|
||||
{
|
||||
public static GoForAPerfect instance { get; set; }
|
||||
|
||||
private Animator pAnim;
|
||||
|
||||
private bool active = false;
|
||||
|
||||
public bool perfect;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
pAnim = transform.GetChild(0).GetChild(0).GetComponent<Animator>();
|
||||
perfect = true;
|
||||
}
|
||||
|
||||
public void Hit()
|
||||
{
|
||||
if (!active) return;
|
||||
pAnim.Play("PerfectIcon_Hit", 0, 0);
|
||||
}
|
||||
|
||||
public void Miss()
|
||||
{
|
||||
if (!active) return;
|
||||
perfect = false;
|
||||
|
||||
GameProfiler.instance.perfect = false;
|
||||
|
||||
transform.GetChild(0).GetChild(1).gameObject.SetActive(false);
|
||||
this.GetComponent<Animator>().Play("GoForAPerfect_Miss");
|
||||
Jukebox.PlayOneShot("perfectMiss");
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
SetActive();
|
||||
transform.GetChild(0).gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
SetInactive();
|
||||
transform.GetChild(0).gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void SetActive()
|
||||
{
|
||||
active = true;
|
||||
}
|
||||
public void SetInactive()
|
||||
{
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -13,6 +13,9 @@ namespace HeavenStudio
|
||||
{
|
||||
public class Initializer : MonoBehaviour
|
||||
{
|
||||
[SerializeField] RenderTexture gameRenderTexture;
|
||||
[SerializeField] RenderTexture overlayRenderTexture;
|
||||
|
||||
public TextAsset level;
|
||||
public AudioClip music;
|
||||
public GameObject canvas;
|
||||
@ -50,7 +53,9 @@ namespace HeavenStudio
|
||||
GameObject MainCamera = Cameras.transform.GetChild(0).gameObject;
|
||||
GameObject CursorCamera = Cameras.transform.GetChild(1).gameObject;
|
||||
GameObject OverlayCamera = Cameras.transform.GetChild(2).gameObject;
|
||||
GameObject GameLetterbox = Cameras.transform.GetChild(3).gameObject;
|
||||
GameObject StaticCamera = Cameras.transform.GetChild(3).gameObject;
|
||||
GameObject GameLetterbox = Cameras.transform.GetChild(4).gameObject;
|
||||
|
||||
|
||||
GameObject Cursor = Instantiate(Resources.Load<GameObject>("Prefabs/Cursor"));
|
||||
Cursor.name = "Cursor";
|
||||
@ -68,6 +73,7 @@ namespace HeavenStudio
|
||||
gameManager.GameCamera = MainCamera.GetComponent<Camera>();
|
||||
gameManager.CursorCam = CursorCamera.GetComponent<Camera>();
|
||||
gameManager.OverlayCamera = OverlayCamera.GetComponent<Camera>();
|
||||
gameManager.StaticCamera = StaticCamera.GetComponent<Camera>();
|
||||
gameManager.GameLetterbox = GameLetterbox;
|
||||
|
||||
GameObject Profiler = Instantiate(Resources.Load<GameObject>("Prefabs/GameProfiler"));
|
||||
@ -87,6 +93,10 @@ namespace HeavenStudio
|
||||
source.outputAudioMixerGroup = Settings.GetMusicMixer();
|
||||
// Conductor.AddComponent<AudioDspTimeKeeper>();
|
||||
|
||||
GlobalGameManager.GameRenderTexture = gameRenderTexture;
|
||||
GlobalGameManager.OverlayRenderTexture = overlayRenderTexture;
|
||||
GlobalGameManager.ResetGameRenderTexture();
|
||||
|
||||
if (editor)
|
||||
{
|
||||
this.GetComponent<HeavenStudio.Editor.Editor>().Init();
|
||||
|
@ -94,9 +94,8 @@ namespace HeavenStudio.Editor
|
||||
|
||||
public void Init()
|
||||
{
|
||||
GameCamera.instance.camera.targetTexture = ScreenRenderTexture;
|
||||
GameManager.instance.StaticCamera.targetTexture = ScreenRenderTexture;
|
||||
GameManager.instance.CursorCam.targetTexture = ScreenRenderTexture;
|
||||
GameManager.instance.OverlayCamera.targetTexture = ScreenRenderTexture;
|
||||
GameLetterbox = GameManager.instance.GameLetterbox;
|
||||
Screen.texture = ScreenRenderTexture;
|
||||
|
||||
@ -501,9 +500,8 @@ namespace HeavenStudio.Editor
|
||||
|
||||
MainCanvas.enabled = false;
|
||||
EditorCamera.enabled = false;
|
||||
GameCamera.instance.camera.targetTexture = null;
|
||||
GameManager.instance.StaticCamera.targetTexture = null;
|
||||
GameManager.instance.CursorCam.enabled = false;
|
||||
GameManager.instance.OverlayCamera.targetTexture = null;
|
||||
fullscreen = true;
|
||||
|
||||
}
|
||||
@ -514,9 +512,8 @@ namespace HeavenStudio.Editor
|
||||
|
||||
MainCanvas.enabled = true;
|
||||
EditorCamera.enabled = true;
|
||||
GameCamera.instance.camera.targetTexture = ScreenRenderTexture;
|
||||
GameManager.instance.StaticCamera.targetTexture = ScreenRenderTexture;
|
||||
GameManager.instance.CursorCam.enabled = true && isCursorEnabled;
|
||||
GameManager.instance.OverlayCamera.targetTexture = ScreenRenderTexture;
|
||||
fullscreen = false;
|
||||
|
||||
GameCamera.instance.camera.rect = new Rect(0, 0, 1, 1);
|
||||
|
@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@ -16,6 +17,8 @@ namespace HeavenStudio.Editor
|
||||
|
||||
public Slider volSlider;
|
||||
public TMP_InputField volLabel;
|
||||
public TMP_Dropdown dspSizeDropdown;
|
||||
public TMP_Dropdown sampleRateDropdown;
|
||||
|
||||
private void Start() {
|
||||
List<TMP_Dropdown.OptionData> dropDownData = new List<TMP_Dropdown.OptionData>();
|
||||
@ -53,16 +56,30 @@ namespace HeavenStudio.Editor
|
||||
|
||||
volSlider.value = GlobalGameManager.MasterVolume;
|
||||
volLabel.text = System.Math.Round(volSlider.value * 100, 2).ToString();
|
||||
|
||||
dspSizeDropdown.onValueChanged.AddListener(delegate
|
||||
{
|
||||
GlobalGameManager.currentDspSize = GlobalGameManager.DSP_BUFFER_SIZES[dspSizeDropdown.value];
|
||||
GlobalGameManager.ChangeAudioSettings(GlobalGameManager.currentDspSize, GlobalGameManager.currentSampleRate);
|
||||
});
|
||||
|
||||
sampleRateDropdown.onValueChanged.AddListener(delegate
|
||||
{
|
||||
GlobalGameManager.currentSampleRate = GlobalGameManager.SAMPLE_RATES[sampleRateDropdown.value];
|
||||
GlobalGameManager.ChangeAudioSettings(GlobalGameManager.currentDspSize, GlobalGameManager.currentSampleRate);
|
||||
});
|
||||
}
|
||||
|
||||
public void WindowFullScreen()
|
||||
{
|
||||
GlobalGameManager.WindowFullScreen();
|
||||
GlobalGameManager.ResetGameRenderTexture();
|
||||
}
|
||||
|
||||
public void WindowConfirmSize()
|
||||
{
|
||||
GlobalGameManager.ChangeScreenSize();
|
||||
GlobalGameManager.ResetGameRenderTexture();
|
||||
}
|
||||
|
||||
public void OnVolSliderChanged()
|
||||
@ -88,6 +105,13 @@ namespace HeavenStudio.Editor
|
||||
|
||||
volSlider.value = GlobalGameManager.MasterVolume;
|
||||
volLabel.text = System.Math.Round(volSlider.value * 100, 2).ToString();
|
||||
|
||||
dspSizeDropdown.ClearOptions();
|
||||
sampleRateDropdown.ClearOptions();
|
||||
dspSizeDropdown.AddOptions(GlobalGameManager.DSP_BUFFER_SIZES.Select(x => x.ToString()).ToList());
|
||||
sampleRateDropdown.AddOptions(GlobalGameManager.SAMPLE_RATES.Select(x => x.ToString()).ToList());
|
||||
dspSizeDropdown.value = GlobalGameManager.DSP_BUFFER_SIZES.ToList().IndexOf(GlobalGameManager.currentDspSize);
|
||||
sampleRateDropdown.value = GlobalGameManager.SAMPLE_RATES.ToList().IndexOf(GlobalGameManager.currentSampleRate);
|
||||
}
|
||||
|
||||
public override void OnCloseTab()
|
||||
|
273
Assets/Scripts/LevelEditor/SettingsDialog/Tabs/GameSettings.cs
Normal file
273
Assets/Scripts/LevelEditor/SettingsDialog/Tabs/GameSettings.cs
Normal file
@ -0,0 +1,273 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
using HeavenStudio.Common;
|
||||
|
||||
namespace HeavenStudio.Editor
|
||||
{
|
||||
public class GameSettings : TabsContent
|
||||
{
|
||||
public static bool InPreview;
|
||||
[SerializeField] Toggle editorOverlaysToggle;
|
||||
[SerializeField] Toggle perfectChallengeToggle;
|
||||
[SerializeField] Toggle sectionMedalsToggle;
|
||||
[SerializeField] Toggle timingDispMinModeToggle;
|
||||
|
||||
[Header("Layout Settings - Header")]
|
||||
[SerializeField] TMP_Text ElementNameText;
|
||||
|
||||
[Header("Layout Settings - General")]
|
||||
[SerializeField] Toggle ElementToggle;
|
||||
|
||||
[SerializeField] TMP_InputField XPosInput;
|
||||
[SerializeField] TMP_InputField YPosInput;
|
||||
[SerializeField] Slider XPosSlider;
|
||||
[SerializeField] Slider YPosSlider;
|
||||
|
||||
[SerializeField] TMP_InputField RotationInput;
|
||||
[SerializeField] Slider RotationSlider;
|
||||
|
||||
[SerializeField] TMP_InputField ScaleInput;
|
||||
[SerializeField] Slider ScaleSlider;
|
||||
|
||||
[Header("Layout Settings - Timing Display")]
|
||||
[SerializeField] GameObject TimingDispTypeContainer;
|
||||
[SerializeField] TMP_Dropdown TimingDispTypeDropdown;
|
||||
|
||||
List<OverlaysManager.OverlayOption> lytElements = new List<OverlaysManager.OverlayOption>();
|
||||
static int currentElementIdx = 0;
|
||||
|
||||
const string fFormat = "0.000";
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CreateDefaultLayout()
|
||||
{
|
||||
PersistentDataManager.gameSettings.timingDisplayComponents = new List<OverlaysManager.TimingDisplayComponent>()
|
||||
{
|
||||
OverlaysManager.TimingDisplayComponent.CreateDefaultDual()
|
||||
};
|
||||
PersistentDataManager.gameSettings.skillStarComponents = new List<OverlaysManager.SkillStarComponent>()
|
||||
{
|
||||
OverlaysManager.SkillStarComponent.CreateDefault()
|
||||
};
|
||||
PersistentDataManager.gameSettings.sectionComponents = new List<OverlaysManager.SectionComponent>()
|
||||
{
|
||||
OverlaysManager.SectionComponent.CreateDefault()
|
||||
};
|
||||
PersistentDataManager.SaveSettings();
|
||||
}
|
||||
|
||||
public void OnEditorOverlaysToggleChanged()
|
||||
{
|
||||
PersistentDataManager.gameSettings.overlaysInEditor = editorOverlaysToggle.isOn;
|
||||
}
|
||||
public void OnPerfectChallengeToggleChanged()
|
||||
{
|
||||
PersistentDataManager.gameSettings.perfectChallengeType = perfectChallengeToggle.isOn ? PersistentDataManager.PerfectChallengeType.On : PersistentDataManager.PerfectChallengeType.Off;
|
||||
}
|
||||
|
||||
public void OnSectionMedalsToggleChanged()
|
||||
{
|
||||
PersistentDataManager.gameSettings.isMedalOn = sectionMedalsToggle.isOn;
|
||||
}
|
||||
|
||||
public void OnTimingDispMinModeToggleChanged()
|
||||
{
|
||||
PersistentDataManager.gameSettings.timingDisplayMinMode = timingDispMinModeToggle.isOn;
|
||||
}
|
||||
|
||||
public override void OnOpenTab()
|
||||
{
|
||||
TimingDispTypeDropdown.ClearOptions();
|
||||
TimingDispTypeDropdown.AddOptions(Enum.GetNames(typeof(OverlaysManager.TimingDisplayComponent.TimingDisplayType)).ToList());
|
||||
|
||||
editorOverlaysToggle.isOn = PersistentDataManager.gameSettings.overlaysInEditor;
|
||||
perfectChallengeToggle.isOn = PersistentDataManager.gameSettings.perfectChallengeType != PersistentDataManager.PerfectChallengeType.Off;
|
||||
sectionMedalsToggle.isOn = PersistentDataManager.gameSettings.isMedalOn;
|
||||
timingDispMinModeToggle.isOn = PersistentDataManager.gameSettings.timingDisplayMinMode;
|
||||
|
||||
if (PersistentDataManager.gameSettings.timingDisplayComponents.Count == 0 &&
|
||||
PersistentDataManager.gameSettings.skillStarComponents.Count == 0 &&
|
||||
PersistentDataManager.gameSettings.sectionComponents.Count == 0)
|
||||
{
|
||||
CreateDefaultLayout();
|
||||
}
|
||||
|
||||
lytElements = new List<OverlaysManager.OverlayOption>();
|
||||
foreach (var c in PersistentDataManager.gameSettings.timingDisplayComponents) { lytElements.Add(c); c.EnablePreview();}
|
||||
foreach (var c in PersistentDataManager.gameSettings.skillStarComponents) { lytElements.Add(c); c.EnablePreview();}
|
||||
foreach (var c in PersistentDataManager.gameSettings.sectionComponents) { lytElements.Add(c); c.EnablePreview();}
|
||||
|
||||
UpdateLayoutSettings();
|
||||
InPreview = true;
|
||||
}
|
||||
|
||||
public override void OnCloseTab()
|
||||
{
|
||||
foreach (var e in lytElements)
|
||||
{
|
||||
e.DisablePreview();
|
||||
}
|
||||
lytElements.Clear();
|
||||
InPreview = false;
|
||||
}
|
||||
|
||||
void UpdateLayoutSettings()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
element.EnablePreview();
|
||||
|
||||
ElementToggle.isOn = element.enable;
|
||||
XPosInput.text = element.position.x.ToString(fFormat);
|
||||
YPosInput.text = element.position.y.ToString(fFormat);
|
||||
XPosSlider.value = element.position.x;
|
||||
YPosSlider.value = element.position.y;
|
||||
RotationInput.text = element.rotation.ToString(fFormat);
|
||||
RotationSlider.value = element.rotation;
|
||||
ScaleInput.text = element.scale.ToString(fFormat);
|
||||
ScaleSlider.value = element.scale;
|
||||
|
||||
if (element is OverlaysManager.TimingDisplayComponent)
|
||||
{
|
||||
TimingDispTypeContainer.SetActive(true);
|
||||
TimingDispTypeDropdown.value = (int)(element as OverlaysManager.TimingDisplayComponent).tdType;
|
||||
ElementNameText.text = "Timing Display";
|
||||
}
|
||||
else
|
||||
{
|
||||
TimingDispTypeContainer.SetActive(false);
|
||||
}
|
||||
if (element is OverlaysManager.SkillStarComponent)
|
||||
{
|
||||
ElementNameText.text = "Skill Star";
|
||||
}
|
||||
if (element is OverlaysManager.SectionComponent)
|
||||
{
|
||||
ElementNameText.text = "Section Progress";
|
||||
}
|
||||
}
|
||||
|
||||
public void OnNextElementButtonClicked()
|
||||
{
|
||||
currentElementIdx = (currentElementIdx + 1) % lytElements.Count;
|
||||
UpdateLayoutSettings();
|
||||
}
|
||||
|
||||
public void OnPrevElementButtonClicked()
|
||||
{
|
||||
currentElementIdx = (currentElementIdx - 1 + lytElements.Count) % lytElements.Count;
|
||||
UpdateLayoutSettings();
|
||||
}
|
||||
|
||||
public void OnElementToggled()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
element.enable = ElementToggle.isOn;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnXPosInputChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
XPosSlider.value = float.Parse(XPosInput.text);
|
||||
element.position.x = XPosSlider.value;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnXPosSliderChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
XPosInput.text = XPosSlider.value.ToString(fFormat);
|
||||
element.position.x = XPosSlider.value;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnYPosInputChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
YPosSlider.value = float.Parse(YPosInput.text);
|
||||
element.position.y = YPosSlider.value;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnYPosSliderChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
YPosInput.text = YPosSlider.value.ToString(fFormat);
|
||||
element.position.y = YPosSlider.value;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnRotationInputChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
RotationSlider.value = float.Parse(RotationInput.text);
|
||||
element.rotation = RotationSlider.value;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnRotationSliderChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
RotationInput.text = RotationSlider.value.ToString(fFormat);
|
||||
element.rotation = RotationSlider.value;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnScaleInputChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
ScaleSlider.value = float.Parse(ScaleInput.text);
|
||||
element.scale = ScaleSlider.value;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnScaleSliderChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx];
|
||||
ScaleInput.text = ScaleSlider.value.ToString(fFormat);
|
||||
element.scale = ScaleSlider.value;
|
||||
element.PositionElement();
|
||||
}
|
||||
|
||||
public void OnTimingDispTypeDropdownChanged()
|
||||
{
|
||||
var element = lytElements[currentElementIdx] as OverlaysManager.TimingDisplayComponent;
|
||||
if (element == null) return;
|
||||
element.tdType = (OverlaysManager.TimingDisplayComponent.TimingDisplayType)TimingDispTypeDropdown.value;
|
||||
bool elHide = element.enable;
|
||||
switch (element.tdType)
|
||||
{
|
||||
case OverlaysManager.TimingDisplayComponent.TimingDisplayType.Dual:
|
||||
element.position = new Vector2(-0.84f, 0);
|
||||
element.rotation = 0f;
|
||||
break;
|
||||
default:
|
||||
element.position = new Vector2(0, -0.8f);
|
||||
element.rotation = 90f;
|
||||
break;
|
||||
}
|
||||
element.scale = 1f;
|
||||
element.enable = elHide;
|
||||
element.PositionElement();
|
||||
UpdateLayoutSettings();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32bac8197392a514388a446353759930
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,6 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
using HeavenStudio;
|
||||
using HeavenStudio.Editor;
|
||||
@ -11,6 +12,7 @@ public class SectionDialog : Dialog
|
||||
{
|
||||
SectionTimelineObj sectionObj;
|
||||
[SerializeField] TMP_InputField sectionName;
|
||||
[SerializeField] Toggle challengeEnable;
|
||||
|
||||
public void SwitchSectionDialog()
|
||||
{
|
||||
@ -29,6 +31,7 @@ public class SectionDialog : Dialog
|
||||
{
|
||||
this.sectionObj = sectionObj;
|
||||
sectionName.text = sectionObj.chartSection.sectionName;
|
||||
challengeEnable.isOn = sectionObj.chartSection.startPerfect;
|
||||
}
|
||||
|
||||
public void DeleteSection()
|
||||
@ -48,4 +51,10 @@ public class SectionDialog : Dialog
|
||||
sectionObj.chartSection.sectionName = name;
|
||||
sectionObj.UpdateLabel();
|
||||
}
|
||||
|
||||
public void SetSectionChallenge()
|
||||
{
|
||||
if (sectionObj == null) return;
|
||||
sectionObj.chartSection.startPerfect = challengeEnable.isOn;
|
||||
}
|
||||
}
|
||||
|
@ -132,10 +132,6 @@ namespace HeavenStudio.Editor.Track
|
||||
[SerializeField] private RectTransform TimelineEventObjRef;
|
||||
[SerializeField] private RectTransform LayersRect;
|
||||
|
||||
[SerializeField] private GameObject TimelineSectionDisplay;
|
||||
[SerializeField] private TMP_Text TimelineSectionText;
|
||||
[SerializeField] private Slider TimelineSectionProgress;
|
||||
|
||||
[Header("Timeline Inputs")]
|
||||
public TMP_InputField FirstBeatOffset;
|
||||
public TMP_InputField StartingTempoSpecialAll;
|
||||
@ -307,7 +303,6 @@ namespace HeavenStudio.Editor.Track
|
||||
timelineState.SetState(CurrentTimelineState.State.Selection);
|
||||
|
||||
AutoBtnUpdate();
|
||||
GameManager.instance.onSectionChange += OnSectionChange;
|
||||
}
|
||||
|
||||
public void FitToSong()
|
||||
@ -387,7 +382,6 @@ 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();
|
||||
|
||||
@ -993,21 +987,6 @@ namespace HeavenStudio.Editor.Track
|
||||
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
|
||||
|
@ -268,7 +268,19 @@ namespace HeavenStudio
|
||||
GameManager.instance.Stop(0);
|
||||
}
|
||||
),
|
||||
new GameAction("skill star", "Skill Star", 1f, true),
|
||||
new GameAction("skill star", "Skill Star", 1f, true)
|
||||
{
|
||||
//temp for testing
|
||||
function = delegate {
|
||||
var e = eventCaller.currentEntity;
|
||||
HeavenStudio.Common.SkillStarManager.instance.DoStarIn(e.beat, e.length);
|
||||
// BeatAction.New(HeavenStudio.Common.SkillStarManager.instance.gameObject, new List<BeatAction.Action>(){
|
||||
// new BeatAction.Action(e.beat + e.length, delegate {
|
||||
// HeavenStudio.Common.SkillStarManager.instance.DoStarJust();
|
||||
// })
|
||||
// });
|
||||
}
|
||||
},
|
||||
new GameAction("toggle inputs", "Toggle Inputs", 0.5f, true,
|
||||
new List<Param>()
|
||||
{
|
||||
@ -391,20 +403,44 @@ namespace HeavenStudio
|
||||
),
|
||||
new GameAction("move camera", "Move Camera", 1f, true, new List<Param>()
|
||||
{
|
||||
new Param("valA", new EntityTypes.Float(-50, 50, 0), "Right / Left"),
|
||||
new Param("valB", new EntityTypes.Float(-50, 50, 0), "Up / Down"),
|
||||
new Param("valC", new EntityTypes.Float(-0, 250, 10), "In / Out"),
|
||||
new Param("ease", EasingFunction.Ease.Linear, "Ease Type")
|
||||
new Param("valA", new EntityTypes.Float(-50, 50, 0), "Right / Left", "Next position on the X axis"),
|
||||
new Param("valB", new EntityTypes.Float(-50, 50, 0), "Up / Down", "Next position on the Y axis"),
|
||||
new Param("valC", new EntityTypes.Float(-0, 250, 10), "In / Out", "Next position on the Z axis"),
|
||||
new Param("ease", EasingFunction.Ease.Linear, "Ease Type"),
|
||||
new Param("axis", GameCamera.CameraAxis.All, "Axis", "The axis to move the camera on" )
|
||||
}
|
||||
),
|
||||
new GameAction("rotate camera", "Rotate Camera", 1f, true, new List<Param>()
|
||||
{
|
||||
new Param("valA", new EntityTypes.Integer(-360, 360, 0), "Pitch"),
|
||||
new Param("valB", new EntityTypes.Integer(-360, 360, 0), "Yaw"),
|
||||
new Param("valC", new EntityTypes.Integer(-360, 360, 0), "Roll"),
|
||||
new Param("ease", EasingFunction.Ease.Linear, "Ease Type")
|
||||
new Param("valA", new EntityTypes.Integer(-360, 360, 0), "Pitch", "Next rotation on the X axis"),
|
||||
new Param("valB", new EntityTypes.Integer(-360, 360, 0), "Yaw", "Next rotation on the Y axis"),
|
||||
new Param("valC", new EntityTypes.Integer(-360, 360, 0), "Roll", "Next rotation on the Z axis"),
|
||||
new Param("ease", EasingFunction.Ease.Linear, "Ease Type"),
|
||||
new Param("axis", GameCamera.CameraAxis.All, "Axis", "The axis to move the camera on" )
|
||||
}
|
||||
),
|
||||
new GameAction("pan view", "Pan Viewport", 1f, true, new List<Param>()
|
||||
{
|
||||
new Param("valA", new EntityTypes.Float(-50, 50, 0), "Right / Left", "Next position on the X axis"),
|
||||
new Param("valB", new EntityTypes.Float(-50, 50, 0), "Up / Down", "Next position on the Y axis"),
|
||||
new Param("ease", EasingFunction.Ease.Linear, "Ease Type"),
|
||||
new Param("axis", StaticCamera.ViewAxis.All, "Axis", "The axis to pan the viewport in" )
|
||||
}
|
||||
),
|
||||
new GameAction("rotate view", "Rotate Viewport", 1f, true, new List<Param>()
|
||||
{
|
||||
new Param("valA", new EntityTypes.Float(-360, 360, 0), "Rotation", "Next viewport rotation"),
|
||||
new Param("ease", EasingFunction.Ease.Linear, "Ease Type"),
|
||||
}
|
||||
),
|
||||
new GameAction("scale view", "Scale Viewport", 1f, true, new List<Param>()
|
||||
{
|
||||
new Param("valA", new EntityTypes.Float(0, 50, 1), "Width", "Next viewport width"),
|
||||
new Param("valB", new EntityTypes.Float(0, 50, 1), "Height", "Next viewport height"),
|
||||
new Param("ease", EasingFunction.Ease.Linear, "Ease Type"),
|
||||
new Param("axis", StaticCamera.ViewAxis.All, "Axis", "The axis to scale the viewport in" )
|
||||
}
|
||||
),
|
||||
|
||||
new GameAction("screen shake", "Screen Shake", 1f, true,
|
||||
new List<Param>()
|
||||
|
@ -10,28 +10,52 @@ namespace HeavenStudio.Common
|
||||
{
|
||||
public static class PersistentDataManager
|
||||
{
|
||||
public enum PerfectChallengeType
|
||||
{
|
||||
Off, // no perfect challenge
|
||||
Arcade, // "arcade rule"
|
||||
Legacy, // "legacy rule"
|
||||
On // "megamix rule"
|
||||
}
|
||||
|
||||
[NonSerialized] public static GameSettings gameSettings;
|
||||
|
||||
public static void CreateDefaultSettings()
|
||||
{
|
||||
gameSettings = new GameSettings();
|
||||
|
||||
gameSettings.isFullscreen = false;
|
||||
|
||||
gameSettings.resolutionIndex = 0;
|
||||
gameSettings.resolutionWidth = GlobalGameManager.DEFAULT_SCREEN_SIZES[gameSettings.resolutionIndex].width;
|
||||
gameSettings.resolutionHeight = GlobalGameManager.DEFAULT_SCREEN_SIZES[gameSettings.resolutionIndex].height;
|
||||
|
||||
gameSettings.masterVolume = 0.8f;
|
||||
|
||||
gameSettings.editorCursorEnable = true;
|
||||
gameSettings = new GameSettings(
|
||||
false,
|
||||
1,
|
||||
GlobalGameManager.DEFAULT_SCREEN_SIZES[1].width,
|
||||
GlobalGameManager.DEFAULT_SCREEN_SIZES[1].height,
|
||||
0.8f,
|
||||
256,
|
||||
44100,
|
||||
true,
|
||||
true,
|
||||
PerfectChallengeType.On,
|
||||
true,
|
||||
false
|
||||
);
|
||||
|
||||
// disable if platform is mac
|
||||
if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor)
|
||||
gameSettings.discordRPCEnable = false;
|
||||
else
|
||||
gameSettings.discordRPCEnable = true;
|
||||
|
||||
|
||||
gameSettings.timingDisplayComponents = new List<OverlaysManager.TimingDisplayComponent>()
|
||||
{
|
||||
OverlaysManager.TimingDisplayComponent.CreateDefaultDual()
|
||||
};
|
||||
gameSettings.skillStarComponents = new List<OverlaysManager.SkillStarComponent>()
|
||||
{
|
||||
OverlaysManager.SkillStarComponent.CreateDefault()
|
||||
};
|
||||
gameSettings.sectionComponents = new List<OverlaysManager.SectionComponent>()
|
||||
{
|
||||
OverlaysManager.SectionComponent.CreateDefault()
|
||||
};
|
||||
|
||||
SaveSettings();
|
||||
}
|
||||
|
||||
@ -68,6 +92,58 @@ namespace HeavenStudio.Common
|
||||
[Serializable]
|
||||
public struct GameSettings
|
||||
{
|
||||
// default settings constructor
|
||||
public GameSettings(
|
||||
bool isFullscreen = false,
|
||||
int resolutionIndex = 0,
|
||||
int resolutionWidth = 1280,
|
||||
int resolutionHeight = 720,
|
||||
float masterVolume = 0.8f,
|
||||
int dspSize = 256,
|
||||
int sampleRate = 44100,
|
||||
bool editorCursorEnable = true,
|
||||
bool discordRPCEnable = true,
|
||||
PerfectChallengeType perfectChallengeType = PerfectChallengeType.On,
|
||||
bool isMedalOn = true,
|
||||
bool timingDisplayMinMode = false,
|
||||
bool overlaysInEditor = true
|
||||
)
|
||||
{
|
||||
this.isFullscreen = isFullscreen;
|
||||
|
||||
this.resolutionIndex = resolutionIndex;
|
||||
this.resolutionWidth = resolutionWidth;
|
||||
this.resolutionHeight = resolutionHeight;
|
||||
|
||||
this.masterVolume = masterVolume;
|
||||
this.dspSize = dspSize;
|
||||
this.sampleRate = sampleRate;
|
||||
|
||||
this.editorCursorEnable = editorCursorEnable;
|
||||
if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor)
|
||||
this.discordRPCEnable = false;
|
||||
else
|
||||
this.discordRPCEnable = true;
|
||||
|
||||
this.perfectChallengeType = perfectChallengeType;
|
||||
this.isMedalOn = isMedalOn;
|
||||
this.timingDisplayMinMode = timingDisplayMinMode;
|
||||
this.overlaysInEditor = overlaysInEditor;
|
||||
|
||||
this.timingDisplayComponents = new List<OverlaysManager.TimingDisplayComponent>()
|
||||
{
|
||||
OverlaysManager.TimingDisplayComponent.CreateDefaultDual()
|
||||
};
|
||||
this.skillStarComponents = new List<OverlaysManager.SkillStarComponent>()
|
||||
{
|
||||
OverlaysManager.SkillStarComponent.CreateDefault()
|
||||
};
|
||||
this.sectionComponents = new List<OverlaysManager.SectionComponent>()
|
||||
{
|
||||
OverlaysManager.SectionComponent.CreateDefault()
|
||||
};
|
||||
}
|
||||
|
||||
// Display / Audio Settings
|
||||
public bool isFullscreen;
|
||||
|
||||
@ -76,11 +152,21 @@ namespace HeavenStudio.Common
|
||||
public int resolutionHeight;
|
||||
|
||||
public float masterVolume;
|
||||
public int dspSize;
|
||||
public int sampleRate;
|
||||
|
||||
// Editor Settings
|
||||
public bool editorCursorEnable;
|
||||
public bool discordRPCEnable;
|
||||
|
||||
// Gameplay Settings
|
||||
public PerfectChallengeType perfectChallengeType;
|
||||
public bool isMedalOn;
|
||||
public bool timingDisplayMinMode;
|
||||
public bool overlaysInEditor;
|
||||
public List<OverlaysManager.TimingDisplayComponent> timingDisplayComponents;
|
||||
public List<OverlaysManager.SkillStarComponent> skillStarComponents;
|
||||
public List<OverlaysManager.SectionComponent> sectionComponents;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
201
Assets/Scripts/StaticCamera.cs
Normal file
201
Assets/Scripts/StaticCamera.cs
Normal file
@ -0,0 +1,201 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
using HeavenStudio.Util;
|
||||
|
||||
namespace HeavenStudio
|
||||
{
|
||||
public class StaticCamera : MonoBehaviour
|
||||
{
|
||||
[SerializeField] RectTransform canvas;
|
||||
[SerializeField] GameObject overlayView;
|
||||
public static StaticCamera instance { get; private set; }
|
||||
public new Camera camera;
|
||||
|
||||
public enum ViewAxis
|
||||
{
|
||||
All,
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
const float AspectRatioWidth = 1;
|
||||
const float AspectRatioHeight = 1;
|
||||
|
||||
private List<DynamicBeatmap.DynamicEntity> panEvents = new List<DynamicBeatmap.DynamicEntity>();
|
||||
private List<DynamicBeatmap.DynamicEntity> scaleEvents = new List<DynamicBeatmap.DynamicEntity>();
|
||||
private List<DynamicBeatmap.DynamicEntity> rotationEvents = new List<DynamicBeatmap.DynamicEntity>();
|
||||
|
||||
static Vector3 defaultPan = new Vector3(0, 0, 0);
|
||||
static Vector3 defaultScale = new Vector3(1, 1, 1);
|
||||
static float defaultRotation = 0;
|
||||
|
||||
private static Vector3 pan;
|
||||
private static Vector3 scale;
|
||||
private static float rotation;
|
||||
|
||||
private static Vector3 panLast;
|
||||
private static Vector3 scaleLast;
|
||||
private static float rotationLast;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
instance = this;
|
||||
camera = this.GetComponent<Camera>();
|
||||
}
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
GameManager.instance.onBeatChanged += OnBeatChanged;
|
||||
|
||||
Reset();
|
||||
|
||||
panLast = defaultPan;
|
||||
scaleLast = defaultScale;
|
||||
rotationLast = defaultRotation;
|
||||
}
|
||||
|
||||
public void OnBeatChanged(float beat)
|
||||
{
|
||||
Reset();
|
||||
|
||||
panEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "pan view" });
|
||||
scaleEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "scale view" });
|
||||
rotationEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "rotate view" });
|
||||
|
||||
panLast = defaultPan;
|
||||
scaleLast = defaultScale;
|
||||
rotationLast = defaultRotation;
|
||||
|
||||
UpdatePan();
|
||||
UpdateRotation();
|
||||
UpdateScale();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
UpdatePan();
|
||||
UpdateRotation();
|
||||
UpdateScale();
|
||||
|
||||
canvas.localPosition = pan;
|
||||
canvas.eulerAngles = new Vector3(0, 0, rotation);
|
||||
canvas.localScale = scale;
|
||||
}
|
||||
|
||||
private void UpdatePan()
|
||||
{
|
||||
foreach (var e in panEvents)
|
||||
{
|
||||
float prog = Conductor.instance.GetPositionFromBeat(e.beat, e.length);
|
||||
if (prog >= 0f)
|
||||
{
|
||||
EasingFunction.Function func = EasingFunction.GetEasingFunction((EasingFunction.Ease) e["ease"]);
|
||||
switch (e["axis"])
|
||||
{
|
||||
case (int) ViewAxis.X:
|
||||
pan.x = func(panLast.x, e["valA"], Mathf.Min(prog, 1f));
|
||||
break;
|
||||
case (int) ViewAxis.Y:
|
||||
pan.y = func(panLast.y, e["valB"], Mathf.Min(prog, 1f));
|
||||
break;
|
||||
default:
|
||||
float dx = func(panLast.x, e["valA"], Mathf.Min(prog, 1f));
|
||||
float dy = func(panLast.y, e["valB"], Mathf.Min(prog, 1f));
|
||||
pan = new Vector3(dx, dy, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prog > 1f)
|
||||
{
|
||||
switch (e["axis"])
|
||||
{
|
||||
case (int) ViewAxis.X:
|
||||
panLast.x = e["valA"];
|
||||
break;
|
||||
case (int) ViewAxis.Y:
|
||||
panLast.y = e["valB"];
|
||||
break;
|
||||
default:
|
||||
panLast = new Vector3(e["valA"], e["valB"], 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRotation()
|
||||
{
|
||||
foreach (var e in rotationEvents)
|
||||
{
|
||||
float prog = Conductor.instance.GetPositionFromBeat(e.beat, e.length);
|
||||
if (prog >= 0f)
|
||||
{
|
||||
EasingFunction.Function func = EasingFunction.GetEasingFunction((EasingFunction.Ease) e["ease"]);
|
||||
rotation = func(rotationLast, -e["valA"], Mathf.Min(prog, 1f));
|
||||
}
|
||||
if (prog > 1f)
|
||||
{
|
||||
rotationLast = -e["valA"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateScale()
|
||||
{
|
||||
foreach (var e in scaleEvents)
|
||||
{
|
||||
float prog = Conductor.instance.GetPositionFromBeat(e.beat, e.length);
|
||||
if (prog >= 0f)
|
||||
{
|
||||
EasingFunction.Function func = EasingFunction.GetEasingFunction((EasingFunction.Ease) e["ease"]);
|
||||
switch (e["axis"])
|
||||
{
|
||||
case (int) ViewAxis.X:
|
||||
scale.x = func(scaleLast.x, e["valA"], Mathf.Min(prog, 1f)) * AspectRatioWidth;
|
||||
break;
|
||||
case (int) ViewAxis.Y:
|
||||
scale.y = func(scaleLast.y, e["valB"], Mathf.Min(prog, 1f)) * AspectRatioHeight;
|
||||
break;
|
||||
default:
|
||||
float dx = func(scaleLast.x, e["valA"], Mathf.Min(prog, 1f)) * AspectRatioWidth;
|
||||
float dy = func(scaleLast.y, e["valB"], Mathf.Min(prog, 1f)) * AspectRatioHeight;
|
||||
scale = new Vector3(dx, dy, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prog > 1f)
|
||||
{
|
||||
switch (e["axis"])
|
||||
{
|
||||
case (int) ViewAxis.X:
|
||||
scaleLast.x = e["valA"] * AspectRatioWidth;
|
||||
break;
|
||||
case (int) ViewAxis.Y:
|
||||
scaleLast.y = e["valB"] * AspectRatioHeight;
|
||||
break;
|
||||
default:
|
||||
scaleLast = new Vector3(e["valA"] * AspectRatioWidth, e["valB"] * AspectRatioHeight, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
pan = defaultPan;
|
||||
scale = defaultScale;
|
||||
rotation = defaultRotation;
|
||||
}
|
||||
|
||||
public void ToggleOverlayView(bool toggle)
|
||||
{
|
||||
overlayView.SetActive(toggle);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/StaticCamera.cs.meta
Normal file
11
Assets/Scripts/StaticCamera.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06f773c6342e2994997dd1dbfb45edda
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/Scripts/UI/Overlays.meta
Normal file
8
Assets/Scripts/UI/Overlays.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04104d67d26331a4faaa333588f757e3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
54
Assets/Scripts/UI/Overlays/ChartSectionDisplay.cs
Normal file
54
Assets/Scripts/UI/Overlays/ChartSectionDisplay.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
using HeavenStudio.Editor;
|
||||
|
||||
namespace HeavenStudio.Common
|
||||
{
|
||||
public class ChartSectionDisplay : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TMP_Text SectionText;
|
||||
[SerializeField] private Slider SectionProgress;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
GameManager.instance.onSectionChange += OnSectionChange;
|
||||
GameManager.instance.onBeatChanged += OnBeatChanged;
|
||||
gameObject.SetActive(GameManager.instance.currentSection != null);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
SectionProgress.value = GameManager.instance.sectionProgress;
|
||||
}
|
||||
|
||||
public void OnBeatChanged(float beat)
|
||||
{
|
||||
gameObject.SetActive(GameManager.instance.currentSection != null);
|
||||
SectionProgress.value = GameManager.instance.sectionProgress;
|
||||
}
|
||||
|
||||
public void OnSectionChange(DynamicBeatmap.ChartSection section)
|
||||
{
|
||||
if (section != null)
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
SectionText.text = section.sectionName;
|
||||
SectionProgress.value = GameManager.instance.sectionProgress;
|
||||
|
||||
if (PersistentDataManager.gameSettings.perfectChallengeType == PersistentDataManager.PerfectChallengeType.Off) return;
|
||||
if (!OverlaysManager.OverlaysEnabled) return;
|
||||
if (section.startPerfect && GoForAPerfect.instance != null && GoForAPerfect.instance.perfect && !GoForAPerfect.instance.gameObject.activeSelf)
|
||||
{
|
||||
GoForAPerfect.instance.Enable(section.beat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/UI/Overlays/ChartSectionDisplay.cs.meta
Normal file
11
Assets/Scripts/UI/Overlays/ChartSectionDisplay.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52530e94ebdc2e343a3aa77a9dfd8e71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
123
Assets/Scripts/UI/Overlays/GoForAPerfect.cs
Normal file
123
Assets/Scripts/UI/Overlays/GoForAPerfect.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using HeavenStudio.Util;
|
||||
|
||||
namespace HeavenStudio.Common
|
||||
{
|
||||
public class GoForAPerfect : MonoBehaviour
|
||||
{
|
||||
public static GoForAPerfect instance { get; set; }
|
||||
|
||||
[SerializeField] Animator texAnim;
|
||||
[SerializeField] Animator pAnim;
|
||||
|
||||
private bool active = false;
|
||||
private bool hiddenActive = false;
|
||||
|
||||
public bool perfect;
|
||||
|
||||
Conductor cond;
|
||||
float lastReportedBeat = 0f;
|
||||
float currentBeat = 0f;
|
||||
long currentBlink = 0;
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
perfect = true;
|
||||
cond = Conductor.instance;
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
gameObject.SetActive(hiddenActive);
|
||||
if (!active) return;
|
||||
if (!OverlaysManager.OverlaysEnabled) return;
|
||||
if (cond == null || !cond.isPlaying) return;
|
||||
|
||||
if (cond.ReportBeat(ref lastReportedBeat))
|
||||
{
|
||||
currentBeat = lastReportedBeat;
|
||||
if (currentBlink != 0)
|
||||
{
|
||||
currentBlink++;
|
||||
if (currentBlink % 2 == 0)
|
||||
{
|
||||
texAnim.Play("GoForAPerfect_Blink", -1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
texAnim.Play("GoForAPerfect_Blink2", -1, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentBlink++;
|
||||
}
|
||||
}
|
||||
else if (cond.songPositionInBeats < lastReportedBeat)
|
||||
{
|
||||
lastReportedBeat = Mathf.Round(cond.songPositionInBeats);
|
||||
}
|
||||
}
|
||||
|
||||
public void Hit()
|
||||
{
|
||||
if (!active) return;
|
||||
if (!OverlaysManager.OverlaysEnabled) return;
|
||||
pAnim.Play("PerfectIcon_Hit", 0, 0);
|
||||
}
|
||||
|
||||
public void Miss()
|
||||
{
|
||||
perfect = false;
|
||||
if (!active) return;
|
||||
SetInactive();
|
||||
if (!OverlaysManager.OverlaysEnabled)
|
||||
{
|
||||
hiddenActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
GameProfiler.instance.perfect = false;
|
||||
|
||||
texAnim.Play("GoForAPerfect_Miss");
|
||||
pAnim.Play("PerfectIcon_Miss", -1, 0);
|
||||
Jukebox.PlayOneShot("perfectMiss");
|
||||
}
|
||||
|
||||
public void Enable(double startBeat)
|
||||
{
|
||||
SetActive();
|
||||
gameObject.SetActive(true);
|
||||
pAnim.gameObject.SetActive(true);
|
||||
texAnim.gameObject.SetActive(true);
|
||||
texAnim.Play("GoForAPerfect_Idle");
|
||||
|
||||
currentBlink = 0;
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
SetInactive();
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void SetActive()
|
||||
{
|
||||
hiddenActive = true;
|
||||
active = true;
|
||||
}
|
||||
public void SetInactive()
|
||||
{
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
284
Assets/Scripts/UI/Overlays/OverlaysManager.cs
Normal file
284
Assets/Scripts/UI/Overlays/OverlaysManager.cs
Normal file
@ -0,0 +1,284 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
namespace HeavenStudio.Common
|
||||
{
|
||||
public class OverlaysManager : MonoBehaviour
|
||||
{
|
||||
public static OverlaysManager instance { get; private set; }
|
||||
public static bool OverlaysEnabled;
|
||||
|
||||
const float WIDTH_SPAN = 10f;
|
||||
const float HEIGHT_SPAN = 10f * (9f / 16f);
|
||||
|
||||
[Header("Prefabs")]
|
||||
[SerializeField] GameObject TimingDisplayPrefab;
|
||||
[SerializeField] GameObject SkillStarPrefab;
|
||||
[SerializeField] GameObject ChartSectionPrefab;
|
||||
|
||||
[Header("Components")]
|
||||
[SerializeField] Transform ComponentHolder;
|
||||
|
||||
List<OverlaysManager.OverlayOption> lytElements = new List<OverlaysManager.OverlayOption>();
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
instance = this;
|
||||
RefreshOverlaysLayout();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void TogleOverlaysVisibility(bool visible)
|
||||
{
|
||||
OverlaysEnabled = visible;
|
||||
RepositionElements();
|
||||
}
|
||||
|
||||
public void RefreshOverlaysLayout()
|
||||
{
|
||||
if (PersistentDataManager.gameSettings.timingDisplayComponents == null || PersistentDataManager.gameSettings.timingDisplayComponents.Count == 0)
|
||||
{
|
||||
PersistentDataManager.gameSettings.timingDisplayComponents = new List<TimingDisplayComponent>()
|
||||
{
|
||||
TimingDisplayComponent.CreateDefaultDual()
|
||||
};
|
||||
}
|
||||
if (PersistentDataManager.gameSettings.skillStarComponents == null || PersistentDataManager.gameSettings.skillStarComponents.Count == 0)
|
||||
{
|
||||
PersistentDataManager.gameSettings.skillStarComponents = new List<SkillStarComponent>()
|
||||
{
|
||||
SkillStarComponent.CreateDefault()
|
||||
};
|
||||
}
|
||||
if (PersistentDataManager.gameSettings.sectionComponents == null || PersistentDataManager.gameSettings.sectionComponents.Count == 0)
|
||||
{
|
||||
PersistentDataManager.gameSettings.sectionComponents = new List<SectionComponent>()
|
||||
{
|
||||
SectionComponent.CreateDefault()
|
||||
};
|
||||
}
|
||||
|
||||
lytElements = new List<OverlaysManager.OverlayOption>();
|
||||
foreach (var c in PersistentDataManager.gameSettings.timingDisplayComponents) { lytElements.Add(c); }
|
||||
foreach (var c in PersistentDataManager.gameSettings.skillStarComponents) { lytElements.Add(c); }
|
||||
foreach (var c in PersistentDataManager.gameSettings.sectionComponents) { lytElements.Add(c); }
|
||||
|
||||
foreach (Transform child in ComponentHolder.transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
foreach (var c in lytElements)
|
||||
{
|
||||
if (c is TimingDisplayComponent) {
|
||||
Debug.Log("TimingDisplayComponent");
|
||||
c.CreateElement(TimingDisplayPrefab, ComponentHolder);
|
||||
}
|
||||
else if (c is SkillStarComponent) {
|
||||
Debug.Log("SkillStarComponent");
|
||||
c.CreateElement(SkillStarPrefab, ComponentHolder);
|
||||
}
|
||||
else if (c is SectionComponent) {
|
||||
Debug.Log("SectionComponent");
|
||||
c.CreateElement(ChartSectionPrefab, ComponentHolder);
|
||||
}
|
||||
c.PositionElement();
|
||||
}
|
||||
}
|
||||
|
||||
void RepositionElements()
|
||||
{
|
||||
lytElements = new List<OverlaysManager.OverlayOption>();
|
||||
foreach (var c in PersistentDataManager.gameSettings.timingDisplayComponents) { lytElements.Add(c); }
|
||||
foreach (var c in PersistentDataManager.gameSettings.skillStarComponents) { lytElements.Add(c); }
|
||||
foreach (var c in PersistentDataManager.gameSettings.sectionComponents) { lytElements.Add(c); }
|
||||
foreach (var c in lytElements)
|
||||
{
|
||||
c.PositionElement();
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class TimingDisplayComponent : OverlayOption
|
||||
{
|
||||
public enum TimingDisplayType
|
||||
{
|
||||
Dual,
|
||||
Single,
|
||||
}
|
||||
|
||||
[NonSerialized] GameObject go2;
|
||||
[SerializeField] public TimingDisplayType tdType;
|
||||
|
||||
public TimingDisplayComponent(TimingDisplayType type, bool enable, Vector2 position, float scale, float rotation)
|
||||
{
|
||||
tdType = type;
|
||||
this.enable = enable;
|
||||
this.position = position;
|
||||
this.scale = scale;
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public override void CreateElement(GameObject prefab, Transform holder)
|
||||
{
|
||||
if (go == null) go = Instantiate(prefab, holder);
|
||||
if (go2 == null) go2 = Instantiate(prefab, holder);
|
||||
}
|
||||
|
||||
public override void PositionElement()
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
switch (tdType)
|
||||
{
|
||||
case TimingDisplayType.Dual:
|
||||
go.transform.localPosition = position * new Vector2(WIDTH_SPAN, HEIGHT_SPAN) * new Vector2(-1, 1);
|
||||
go.transform.localScale = Vector3.one * scale;
|
||||
go.transform.localRotation = Quaternion.Euler(0, 0, -rotation);
|
||||
|
||||
go2.transform.localPosition = position * new Vector2(WIDTH_SPAN, HEIGHT_SPAN);
|
||||
go2.transform.localScale = Vector3.one * scale;
|
||||
go2.transform.localRotation = Quaternion.Euler(0, 0, rotation);
|
||||
|
||||
go.SetActive(enable && OverlaysManager.OverlaysEnabled);
|
||||
go2.SetActive(enable && OverlaysManager.OverlaysEnabled);
|
||||
break;
|
||||
case TimingDisplayType.Single:
|
||||
go.transform.localPosition = position * new Vector2(WIDTH_SPAN, HEIGHT_SPAN);
|
||||
go.transform.localScale = Vector3.one * scale;
|
||||
go.transform.localRotation = Quaternion.Euler(0, 0, rotation);
|
||||
go.SetActive(enable && OverlaysManager.OverlaysEnabled);
|
||||
go2.SetActive(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void EnablePreview() {}
|
||||
public override void DisablePreview() {}
|
||||
|
||||
public static TimingDisplayComponent CreateDefaultDual()
|
||||
{
|
||||
return new TimingDisplayComponent(TimingDisplayType.Dual, true, new Vector2(-0.84f, 0), 1f, 0f);
|
||||
}
|
||||
|
||||
public static TimingDisplayComponent CreateDefaultSingle()
|
||||
{
|
||||
return new TimingDisplayComponent(TimingDisplayType.Single, true, new Vector2(0, -0.8f), 1f, 90f);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SkillStarComponent : OverlayOption
|
||||
{
|
||||
public SkillStarComponent(bool enable, Vector2 position, float scale, float rotation)
|
||||
{
|
||||
this.enable = enable;
|
||||
this.position = position;
|
||||
this.scale = scale;
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public override void PositionElement()
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
go.transform.localPosition = position * new Vector2(WIDTH_SPAN, HEIGHT_SPAN);
|
||||
go.transform.localScale = Vector3.one * scale;
|
||||
go.transform.localRotation = Quaternion.Euler(0, 0, rotation);
|
||||
go.SetActive(enable && OverlaysManager.OverlaysEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
public override void EnablePreview() { SkillStarManager.instance?.DoStarPreview(); }
|
||||
public override void DisablePreview() { SkillStarManager.instance.ResetStarPreview(); }
|
||||
|
||||
public static SkillStarComponent CreateDefault()
|
||||
{
|
||||
return new SkillStarComponent(true, new Vector2(0.75f, -0.7f), 1f, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SectionComponent : OverlayOption
|
||||
{
|
||||
public SectionComponent(bool enable, Vector2 position, float scale, float rotation)
|
||||
{
|
||||
this.enable = enable;
|
||||
this.position = position;
|
||||
this.scale = scale;
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public override void PositionElement()
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
go.transform.localPosition = position * new Vector2(WIDTH_SPAN, HEIGHT_SPAN);
|
||||
go.transform.localScale = Vector3.one * scale;
|
||||
go.transform.localRotation = Quaternion.Euler(0, 0, rotation);
|
||||
go.SetActive(enable && OverlaysManager.OverlaysEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
public override void EnablePreview()
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
go.GetComponent<Image>().enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DisablePreview()
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
go.GetComponent<Image>().enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static SectionComponent CreateDefault()
|
||||
{
|
||||
return new SectionComponent(true, new Vector2(0.7f, 0.765f), 1f, 0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public abstract class OverlayOption
|
||||
{
|
||||
static long uuidCounter = 0;
|
||||
[NonSerialized] protected GameObject go;
|
||||
[NonSerialized] public long uuid = GenerateUUID();
|
||||
[SerializeField] public bool enable;
|
||||
[SerializeField] public Vector2 position;
|
||||
[SerializeField] public float scale;
|
||||
[SerializeField] public float rotation;
|
||||
|
||||
static long GenerateUUID()
|
||||
{
|
||||
return uuidCounter++;
|
||||
}
|
||||
|
||||
public virtual void CreateElement(GameObject prefab, Transform holder)
|
||||
{
|
||||
if (go == null)
|
||||
go = Instantiate(prefab, holder);
|
||||
}
|
||||
|
||||
public abstract void PositionElement();
|
||||
public abstract void EnablePreview();
|
||||
public abstract void DisablePreview();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/UI/Overlays/OverlaysManager.cs.meta
Normal file
11
Assets/Scripts/UI/Overlays/OverlaysManager.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c9513d62ced05840a5db89f2a529a71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
77
Assets/Scripts/UI/Overlays/SectionMedalsManager.cs
Normal file
77
Assets/Scripts/UI/Overlays/SectionMedalsManager.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using HeavenStudio.Util;
|
||||
using HeavenStudio.Games;
|
||||
|
||||
namespace HeavenStudio.Common
|
||||
{
|
||||
public class SectionMedalsManager : MonoBehaviour
|
||||
{
|
||||
public static SectionMedalsManager instance { get; private set; }
|
||||
|
||||
[SerializeField] GameObject MedalsHolder;
|
||||
[SerializeField] GameObject MedalOkPrefab;
|
||||
[SerializeField] GameObject MedalMissPrefab;
|
||||
|
||||
Conductor cond;
|
||||
bool isMedalsStarted = false;
|
||||
bool isMedalsEligible = true;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
instance = this;
|
||||
cond = Conductor.instance;
|
||||
GameManager.instance.onSectionChange += OnSectionChange;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void MakeIneligible()
|
||||
{
|
||||
isMedalsEligible = false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
isMedalsStarted = false;
|
||||
isMedalsEligible = true;
|
||||
foreach (Transform child in MedalsHolder.transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSectionChange(DynamicBeatmap.ChartSection section)
|
||||
{
|
||||
if (section == null) return;
|
||||
Debug.Log(PersistentDataManager.gameSettings.isMedalOn);
|
||||
if (PersistentDataManager.gameSettings.isMedalOn && !isMedalsStarted)
|
||||
{
|
||||
isMedalsStarted = true;
|
||||
isMedalsEligible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject medal = Instantiate(isMedalsEligible ? MedalOkPrefab : MedalMissPrefab, MedalsHolder.transform);
|
||||
medal.SetActive(true);
|
||||
isMedalsEligible = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnRemixEnd()
|
||||
{
|
||||
if (PersistentDataManager.gameSettings.isMedalOn && isMedalsStarted)
|
||||
{
|
||||
GameObject medal = Instantiate(isMedalsEligible ? MedalOkPrefab : MedalMissPrefab, MedalsHolder.transform);
|
||||
medal.SetActive(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/UI/Overlays/SectionMedalsManager.cs.meta
Normal file
11
Assets/Scripts/UI/Overlays/SectionMedalsManager.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93e2705ea532cf24d8c161d8762aeccc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
123
Assets/Scripts/UI/Overlays/SkillStarManager.cs
Normal file
123
Assets/Scripts/UI/Overlays/SkillStarManager.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using HeavenStudio.Util;
|
||||
using HeavenStudio.Games;
|
||||
|
||||
namespace HeavenStudio.Common
|
||||
{
|
||||
public class SkillStarManager : MonoBehaviour
|
||||
{
|
||||
public enum StarState
|
||||
{
|
||||
None,
|
||||
In,
|
||||
Collected,
|
||||
Out
|
||||
}
|
||||
public static SkillStarManager instance { get; private set; }
|
||||
[SerializeField] private Animator starAnim;
|
||||
[SerializeField] private ParticleSystem starParticle;
|
||||
|
||||
public float StarTargetTime { get { return starStart + starLength; } }
|
||||
public bool IsEligible { get; private set; }
|
||||
|
||||
float starStart = float.MaxValue;
|
||||
float starLength = float.MaxValue;
|
||||
StarState state = StarState.None;
|
||||
Conductor cond;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
instance = this;
|
||||
cond = Conductor.instance;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
if (cond.songPositionInBeatsAsDouble > starStart && state == StarState.In)
|
||||
{
|
||||
double offset = cond.SecsToBeats(Minigame.AceStartTime()-1, cond.GetBpmAtBeat(StarTargetTime));
|
||||
if (cond.songPositionInBeatsAsDouble <= starStart + starLength + offset)
|
||||
starAnim.DoScaledAnimation("StarIn", starStart, starLength + (float)offset);
|
||||
else
|
||||
starAnim.Play("StarIn", -1, 1f);
|
||||
|
||||
offset = cond.SecsToBeats(Minigame.AceEndTime()-1, cond.GetBpmAtBeat(StarTargetTime));
|
||||
if (cond.songPositionInBeatsAsDouble > starStart + starLength + offset)
|
||||
KillStar();
|
||||
}
|
||||
}
|
||||
|
||||
public void DoStarPreview()
|
||||
{
|
||||
if (starAnim == null) return;
|
||||
starAnim.Play("StarJust", -1, 0.5f);
|
||||
starAnim.speed = 0f;
|
||||
}
|
||||
|
||||
public void ResetStarPreview()
|
||||
{
|
||||
if (starAnim == null) return;
|
||||
starAnim.Play("NoPose", -1, 0f);
|
||||
starAnim.speed = 1f;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
IsEligible = false;
|
||||
cond = Conductor.instance;
|
||||
state = StarState.None;
|
||||
starAnim.Play("NoPose", -1, 0f);
|
||||
starAnim.speed = 1f;
|
||||
starStart = float.MaxValue;
|
||||
starLength = float.MaxValue;
|
||||
}
|
||||
|
||||
public void DoStarIn(float beat, float length)
|
||||
{
|
||||
if (!OverlaysManager.OverlaysEnabled) return;
|
||||
IsEligible = true;
|
||||
state = StarState.In;
|
||||
starStart = beat;
|
||||
starLength = length;
|
||||
|
||||
TimingAccuracyDisplay.instance.StartStarFlash();
|
||||
|
||||
starAnim.DoScaledAnimation("StarIn", beat, length);
|
||||
}
|
||||
|
||||
public bool DoStarJust()
|
||||
{
|
||||
if (state == StarState.In &&
|
||||
cond.songPositionInBeatsAsDouble >= StarTargetTime + cond.SecsToBeats(Minigame.AceStartTime()-1, cond.GetBpmAtBeat(StarTargetTime)) &&
|
||||
cond.songPositionInBeatsAsDouble <= StarTargetTime + cond.SecsToBeats(Minigame.AceEndTime()-1, cond.GetBpmAtBeat(StarTargetTime))
|
||||
)
|
||||
{
|
||||
state = StarState.Collected;
|
||||
starAnim.Play("StarJust", -1, 0f);
|
||||
starParticle.Play();
|
||||
Jukebox.PlayOneShot("skillStar");
|
||||
|
||||
TimingAccuracyDisplay.instance.StopStarFlash();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void KillStar()
|
||||
{
|
||||
if (state == StarState.In && cond.songPositionInBeatsAsDouble >= starStart + starLength*0.5f || !cond.isPlaying)
|
||||
{
|
||||
IsEligible = false;
|
||||
state = StarState.Out;
|
||||
starAnim.Play("NoPose", -1, 0f);
|
||||
|
||||
TimingAccuracyDisplay.instance.StopStarFlash();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/UI/Overlays/SkillStarManager.cs.meta
Normal file
11
Assets/Scripts/UI/Overlays/SkillStarManager.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0521855ace8165a44b98e3d0022da114
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
172
Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs
Normal file
172
Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using HeavenStudio.Games;
|
||||
|
||||
namespace HeavenStudio.Common
|
||||
{
|
||||
public class TimingAccuracyDisplay : MonoBehaviour
|
||||
{
|
||||
public enum Rating
|
||||
{
|
||||
NG,
|
||||
OK,
|
||||
Just
|
||||
}
|
||||
|
||||
public static TimingAccuracyDisplay instance { get; private set; }
|
||||
|
||||
[SerializeField] GameObject NG;
|
||||
[SerializeField] GameObject OK;
|
||||
[SerializeField] GameObject Just;
|
||||
[SerializeField] GameObject MinimalJust;
|
||||
[SerializeField] GameObject MinimalOK;
|
||||
[SerializeField] GameObject MinimalNG;
|
||||
|
||||
[SerializeField] Animator MetreAnim;
|
||||
|
||||
[SerializeField] Transform arrowTransform;
|
||||
[SerializeField] Transform barTransform;
|
||||
[SerializeField] Transform barJustTransform;
|
||||
[SerializeField] Transform barOKTransform;
|
||||
[SerializeField] Transform barNGTransform;
|
||||
|
||||
float targetArrowPos = 0f;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
arrowTransform.localPosition = Vector3.Lerp(arrowTransform.localPosition, new Vector3(0, targetArrowPos, 0), 4f * Time.deltaTime);
|
||||
}
|
||||
|
||||
public void ResetArrow()
|
||||
{
|
||||
targetArrowPos = 0f;
|
||||
arrowTransform.localPosition = Vector3.zero;
|
||||
StopStarFlash();
|
||||
|
||||
NG.GetComponent<ParticleSystem>().Stop();
|
||||
OK.GetComponent<ParticleSystem>().Stop();
|
||||
Just.GetComponent<ParticleSystem>().Stop();
|
||||
MinimalNG.GetComponent<ParticleSystem>().Stop();
|
||||
MinimalOK.GetComponent<ParticleSystem>().Stop();
|
||||
MinimalJust.GetComponent<ParticleSystem>().Stop();
|
||||
}
|
||||
|
||||
public void StartStarFlash()
|
||||
{
|
||||
MetreAnim.Play("StarWarn", -1, 0f);
|
||||
}
|
||||
|
||||
public void StopStarFlash()
|
||||
{
|
||||
MetreAnim.Play("NoPose", -1, 0f);
|
||||
}
|
||||
|
||||
public void MakeAccuracyVfx(double time, bool late = false)
|
||||
{
|
||||
if (!OverlaysManager.OverlaysEnabled) return;
|
||||
GameObject it;
|
||||
Rating type = Rating.NG;
|
||||
|
||||
// centre of the transfor would be "perfect ace"
|
||||
// move the object up or down the bar depending on hit time
|
||||
// use bar's scale Y for now, we're waiting for proper assets
|
||||
|
||||
// this probably doesn't work
|
||||
float frac = 0f;
|
||||
float y = barTransform.position.y;
|
||||
|
||||
// SetArrowPos(time);
|
||||
|
||||
// no Clamp() because double
|
||||
time = System.Math.Max(Minigame.EarlyTime(), System.Math.Min(Minigame.EndTime(), time));
|
||||
|
||||
if (time >= Minigame.AceStartTime() && time <= Minigame.AceEndTime())
|
||||
{
|
||||
type = Rating.Just;
|
||||
frac = (float)((time - Minigame.AceStartTime()) / (Minigame.AceEndTime() - Minigame.AceStartTime()));
|
||||
y = barJustTransform.localScale.y * frac - (barJustTransform.localScale.y * 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (time > 1.0)
|
||||
{
|
||||
// goes "down"
|
||||
if (time <= Minigame.LateTime())
|
||||
{
|
||||
type = Rating.OK;
|
||||
frac = (float)((time - Minigame.AceEndTime()) / (Minigame.LateTime() - Minigame.AceEndTime()));
|
||||
y = ((barOKTransform.localScale.y - barJustTransform.localScale.y) * frac) + barJustTransform.localScale.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = Rating.NG;
|
||||
frac = (float)((time - Minigame.LateTime()) / (Minigame.EndTime() - Minigame.LateTime()));
|
||||
y = ((barNGTransform.localScale.y - barOKTransform.localScale.y) * frac) + barOKTransform.localScale.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// goes "up"
|
||||
if (time >= Minigame.PerfectTime())
|
||||
{
|
||||
type = Rating.OK;
|
||||
frac = (float)((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime()));
|
||||
y = ((barOKTransform.localScale.y - barJustTransform.localScale.y) * -frac) - barJustTransform.localScale.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = Rating.NG;
|
||||
frac = (float)((time - Minigame.EarlyTime()) / (Minigame.PerfectTime() - Minigame.EarlyTime()));
|
||||
y = ((barNGTransform.localScale.y - barOKTransform.localScale.y) * -frac) - barOKTransform.localScale.y;
|
||||
}
|
||||
}
|
||||
y *= -0.5f;
|
||||
}
|
||||
|
||||
targetArrowPos = (targetArrowPos + y) * 0.5f;
|
||||
|
||||
if (PersistentDataManager.gameSettings.timingDisplayMinMode)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Rating.OK:
|
||||
it = MinimalOK;
|
||||
break;
|
||||
case Rating.Just:
|
||||
it = MinimalJust;
|
||||
break;
|
||||
default:
|
||||
it = MinimalNG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Rating.OK:
|
||||
it = OK;
|
||||
break;
|
||||
case Rating.Just:
|
||||
it = Just;
|
||||
break;
|
||||
default:
|
||||
it = NG;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
it.transform.position = barTransform.position + new Vector3(0, barTransform.localScale.y * y, 0);
|
||||
it.GetComponent<ParticleSystem>().Play();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs.meta
Normal file
11
Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a91127b0615e4d341bcde412b3e92f93
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user