Play Mode Features Part 1 (#413)

* add pause menu assets

* layout and animation for pause

* make play mode prefab function

re-assign unused class inheritance

* remove filepath

* don't init medals twice

* remove PlayerActionObject

* initial attempt at anti-note lock

TODO: circumvent inputs clearing themselves making the functionality not work

* properly implement input lock prevention

* fix error on editor open

* functional pause menu

* bugfix

* make unpausing not reset current play statistics

* serialize initializer components in inspector instead of procedurally generating

* sanity check

* note for fade

* make flashes in the camera prefabs instead of in world space

remove / reorganize script files
address issue #411

* fix bug with perfect campaign

make minigame transitions hide the game canvas
adjust animation of the song credits textbox

* fully functional intro scene (placeholder for future title screen)

refactored entire game loading procedure
re-organized some files

* add interaction query to disclaimer text

* reword legal

* anchor section medals to section display

more tempo change placement controls

* operation order bugfix

* prep for future ratings and stats

* loading text

* autoload opening scene

* splash screen adjustments

added setting to force enable splash screen

* adjust setting entry
This commit is contained in:
minenice55
2023-05-07 16:33:15 -04:00
committed by GitHub
parent 6c0fcca922
commit caf7d9465f
183 changed files with 17863 additions and 2247 deletions

View File

@ -1,8 +1,8 @@
using System;
public static class AppInfo {
public const string Version = "0.0.969";
public static readonly DateTime Date = new DateTime(2023, 04, 23, 17, 57, 04, 196, DateTimeKind.Utc);
public const string Version = "0.0.974";
public static readonly DateTime Date = new DateTime(2023, 05, 07, 18, 03, 45, 426, DateTimeKind.Utc);
}

View File

@ -67,7 +67,7 @@ namespace HeavenStudio
// pitch values
private float timelinePitch = 1f;
private float minigamePitch = 1f;
public float SongPitch { get => timelinePitch * minigamePitch; }
public float SongPitch { get => isPaused ? 0f : (timelinePitch * minigamePitch); }
public void SetTimelinePitch(float pitch)
{
@ -87,23 +87,23 @@ namespace HeavenStudio
instance = this;
}
public void SetBeat(float beat)
public void SetBeat(double beat)
{
float secFromBeat = (float) GetSongPosFromBeat(beat);
double secFromBeat = GetSongPosFromBeat(beat);
if (musicSource.clip != null)
{
if (secFromBeat < musicSource.clip.length)
musicSource.time = secFromBeat;
musicSource.time = (float) secFromBeat;
else
musicSource.time = 0;
}
GameManager.instance.SetCurrentEventToClosest(beat);
GameManager.instance.SetCurrentEventToClosest((float) beat);
songPosBeat = beat;
}
public void Play(float beat)
public void Play(double beat)
{
GameManager.instance.SortEventsList();
bool negativeOffset = firstBeatOffset < 0f;

View File

@ -1,13 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Destroy : MonoBehaviour
{
public float time;
private void Start()
{
Destroy(this.gameObject, time);
}
}

View File

@ -110,12 +110,9 @@ namespace HeavenStudio
{
List<DynamicBeatmap.DynamicEntity> temp1 = GameManager.instance.Beatmap.entities.FindAll(c => c.datamodel.Split('/')[0] == gameName);
List<DynamicBeatmap.DynamicEntity> temp2 = new List<DynamicBeatmap.DynamicEntity>();
for (int i = 0; i < temp1.Count; i++)
foreach (string s in include)
{
if (include.Any(temp1[i].datamodel.Split('/')[1].Contains))
{
temp2.Add(temp1[i]);
}
temp2.AddRange(temp1.FindAll(c => c.datamodel.Split('/')[1].Equals(s)));
}
return temp2;
}
@ -124,32 +121,13 @@ namespace HeavenStudio
{
List<DynamicBeatmap.DynamicEntity> temp1 = GameManager.instance.Beatmap.entities.FindAll(c => c.datamodel.Split('/')[0] == gameName);
List<DynamicBeatmap.DynamicEntity> temp2 = new List<DynamicBeatmap.DynamicEntity>();
for (int i = 0; i < temp1.Count; i++)
foreach (string s in exclude)
{
if (!exclude.Any(temp1[i].datamodel.Split('/')[1].Contains))
{
temp2.Add(temp1[i]);
}
temp2.AddRange(temp1.FindAll(c => !c.datamodel.Split('/')[1].Equals(s)));
}
return temp2;
}
public static List<DynamicBeatmap.DynamicEntity> GetAllPlayerEntities(string gameName)
{
return GameManager.instance.playerEntities.FindAll(c => c.datamodel.Split('/')[0] == gameName);
}
public static List<DynamicBeatmap.DynamicEntity> GetAllPlayerEntitiesExcept(string gameName)
{
return GameManager.instance.playerEntities.FindAll(c => c.datamodel.Split('/')[0] != gameName);
}
// elaborate as fuck, boy
public static List<DynamicBeatmap.DynamicEntity> GetAllPlayerEntitiesExceptBeforeBeat(string gameName, float beat)
{
return GameManager.instance.playerEntities.FindAll(c => c.datamodel.Split('/')[0] != gameName && c.beat < beat);
}
public static List<Minigames.Minigame> FXOnlyGames()
{
return instance.minigames.FindAll(c => c.fxOnly == true).ToList();

View File

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

View File

@ -11,61 +11,64 @@ using UnityEngine.Audio;
namespace HeavenStudio
{
public class Initializer : MonoBehaviour
public class GameInitializer : MonoBehaviour
{
[SerializeField] RenderTexture gameRenderTexture;
[SerializeField] RenderTexture overlayRenderTexture;
public TextAsset level;
public AudioClip music;
public GameObject canvas;
[SerializeField] HeavenStudio.Editor.Editor editorGO;
[SerializeField] String debug_cmdFile;
[SerializeField] GameManager gameManager;
[SerializeField] GameObject MainCamera;
[SerializeField] GameObject CursorCamera;
[SerializeField] GameObject OverlayCamera;
[SerializeField] GameObject StaticCamera;
[SerializeField] GameObject Cursor;
[SerializeField] GameObject Profiler;
public bool debugUI;
public bool playOnStart = false;
public bool editor = false;
public bool fromCmd = false;
string json = "";
string ext = "";
private void Start()
{
string[] args = System.Environment.GetCommandLineArgs();
string input = "";
for (int i = 1; i < args.Length; i++) {
// first arg is always this executable
Debug.Log(args[i]);
if (args[i].IndexOfAny(Path.GetInvalidPathChars()) == -1)
if (debug_cmdFile != string.Empty)
{
if (debug_cmdFile.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
if (File.Exists(args[i]))
if (File.Exists(debug_cmdFile))
{
input = args[i];
editor = false;
input = debug_cmdFile;
fromCmd = true;
playOnStart = true;
}
}
else if (args[i] == "-debug")
{
debugUI = true;
}
}
GameObject Cameras = Instantiate(Resources.Load<GameObject>("Prefabs/Cameras")); Cameras.name = "Cameras";
GameObject MainCamera = Cameras.transform.GetChild(0).gameObject;
GameObject CursorCamera = Cameras.transform.GetChild(1).gameObject;
GameObject OverlayCamera = Cameras.transform.GetChild(2).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";
else if (OpeningManager.OnOpenFile is not null or "")
{
if (editorGO == null && OpeningManager.OnOpenFile.IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
if (File.Exists(OpeningManager.OnOpenFile))
{
input = OpeningManager.OnOpenFile;
fromCmd = true;
playOnStart = true;
}
}
OpeningManager.OnOpenFile = null;
}
GameObject Games = new GameObject();
Games.name = "Games";
GameObject GameManager = new GameObject();
GameManager.name = "GameManager";
GameManager gameManager = GameManager.AddComponent<GameManager>();
gameManager.playOnStart = playOnStart;
gameManager.GamesHolder = Games;
@ -75,9 +78,7 @@ namespace HeavenStudio
gameManager.OverlayCamera = OverlayCamera.GetComponent<Camera>();
gameManager.StaticCamera = StaticCamera.GetComponent<Camera>();
GameObject Profiler = Instantiate(Resources.Load<GameObject>("Prefabs/GameProfiler"));
Profiler.name = "GameProfiler";
if (!debugUI)
if (!debugUI && Profiler != null)
{
Profiler.GetComponent<DebugUI>().enabled = false;
Profiler.transform.GetChild(0).gameObject.SetActive(false);
@ -86,7 +87,6 @@ namespace HeavenStudio
GameObject Conductor = new GameObject();
Conductor.name = "Conductor";
AudioSource source = Conductor.AddComponent<AudioSource>();
source.clip = music;
Conductor.AddComponent<Conductor>();
Conductor.GetComponent<Conductor>().musicSource = source;
source.outputAudioMixerGroup = Settings.GetMusicMixer();
@ -96,23 +96,18 @@ namespace HeavenStudio
GlobalGameManager.OverlayRenderTexture = overlayRenderTexture;
GlobalGameManager.ResetGameRenderTexture();
if (editor)
if (editorGO == null)
{
this.GetComponent<HeavenStudio.Editor.Editor>().Init();
}
else
{
this.GetComponent<HeavenStudio.Editor.Editor>().enabled = false;
this.GetComponent<HeavenStudio.Editor.EditorTheme>().enabled = false;
this.GetComponent<HeavenStudio.Editor.BoxSelection>().enabled = false;
canvas.SetActive(false);
OpenCmdRemix(input);
Debug.Log(json);
gameManager.txt = json;
gameManager.ext = ext;
gameManager.Init();
}
else
{
editorGO.Init();
}
}
public void OpenCmdRemix(string path)

View File

@ -14,36 +14,35 @@ namespace HeavenStudio
public class GameManager : MonoBehaviour
{
[Header("Lists")]
public DynamicBeatmap Beatmap = new DynamicBeatmap();
[HideInInspector] public List<DynamicBeatmap.DynamicEntity> playerEntities = new List<DynamicBeatmap.DynamicEntity>();
[NonSerialized] public DynamicBeatmap Beatmap = new DynamicBeatmap();
private List<GameObject> preloadedGames = new List<GameObject>();
public List<GameObject> SoundObjects = new List<GameObject>();
[NonSerialized] public List<GameObject> SoundObjects = new List<GameObject>();
[Header("Components")]
public string txt;
public string ext;
public Camera GameCamera, CursorCam, OverlayCamera, StaticCamera;
public CircleCursor CircleCursor;
[HideInInspector] public GameObject GamesHolder;
public Games.Global.Flash fade;
public Games.Global.Filter filter;
public GameObject textbox;
[NonSerialized] public Camera GameCamera, CursorCam, OverlayCamera, StaticCamera;
[NonSerialized] public CircleCursor CircleCursor;
[NonSerialized] public GameObject GamesHolder;
[NonSerialized] public Games.Global.Flash fade;
[NonSerialized] public Games.Global.Filter filter;
[Header("Games")]
public string currentGame;
[NonSerialized] public string currentGame;
Coroutine currentGameSwitchIE;
[Header("Properties")]
public int currentEvent, currentTempoEvent, currentVolumeEvent, currentSectionEvent,
[NonSerialized] public string txt = null;
[NonSerialized] public string ext = null;
[NonSerialized] public int currentEvent, currentTempoEvent, currentVolumeEvent, currentSectionEvent,
currentPreEvent, currentPreSwitch, currentPreSequence;
public float endBeat;
public float startOffset;
public bool playOnStart;
public float startBeat;
[NonSerialized] public float endBeat;
[NonSerialized] public float startOffset;
[NonSerialized] public bool playOnStart;
[NonSerialized] public float startBeat;
[NonSerialized] public GameObject currentGameO;
public bool autoplay;
public bool canInput = true;
public DynamicBeatmap.ChartSection currentSection, nextSection;
[NonSerialized] public bool autoplay;
[NonSerialized] public bool canInput = true;
[NonSerialized] public DynamicBeatmap.ChartSection currentSection, nextSection;
public float sectionProgress { get; private set; }
public event Action<float> onBeatChanged;
@ -86,6 +85,16 @@ namespace HeavenStudio
}
bool skillStarCollected = false;
// cleared sections
List<bool> clearedSections = new List<bool>();
public bool ClearedSection
{
set
{
clearedSections.Add(value);
}
}
private void Awake()
{
// autoplay = true;
@ -97,24 +106,10 @@ namespace HeavenStudio
currentPreEvent= 0;
currentPreSwitch = 0;
currentPreSequence = 0;
this.transform.localScale = new Vector3(30000000, 30000000);
SpriteRenderer sp = this.gameObject.AddComponent<SpriteRenderer>();
sp.enabled = false;
sp.color = Color.black;
sp.sprite = Resources.Load<Sprite>("Sprites/GeneralPurpose/Square");
sp.sortingOrder = 30000;
gameObject.layer = LayerMask.NameToLayer("Flash");
GameObject fade = new GameObject("flash");
this.fade = fade.AddComponent<Games.Global.Flash>();
GameObject filter = new GameObject("filter");
this.filter = filter.AddComponent<Games.Global.Filter>();
GlobalGameManager.Init();
eventCaller = this.gameObject.AddComponent<EventCaller>();
eventCaller.GamesHolder = GamesHolder.transform;
eventCaller.Init();
@ -123,23 +118,23 @@ namespace HeavenStudio
Conductor.instance.firstBeatOffset = Beatmap.firstBeatOffset;
// note: serialize this shit in the inspector //
GameObject textbox = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Textbox"));
textbox.name = "Textbox";
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 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";
GameObject skillStarDisp = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Overlays/SkillStar"));
skillStarDisp.name = "SkillStar";
GameObject overlays = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Overlays"));
overlays.name = "Overlays";
GoForAPerfect.instance.Disable();
GoForAPerfect.instance.Disable();
/////
if (txt != null && ext != null)
if (txt != null && ext != null && txt.Length != 0 && ext.Length != 0)
{
LoadRemix(txt, ext);
}
@ -162,7 +157,7 @@ namespace HeavenStudio
if (playOnStart)
{
Play(startBeat);
StartCoroutine(WaitReadyAndPlayCo(startBeat));
}
}
@ -204,7 +199,10 @@ namespace HeavenStudio
Conductor.instance.SetBpm(Beatmap.bpm);
Conductor.instance.SetVolume(Beatmap.musicVolume);
Conductor.instance.firstBeatOffset = Beatmap.firstBeatOffset;
Stop(0);
if (!playOnStart)
{
Stop(0);
}
SetCurrentEventToClosest(0);
if (Beatmap.entities.Count >= 1)
@ -319,8 +317,6 @@ namespace HeavenStudio
private void Update()
{
PlayerInput.UpdateInputControllers();
if (BeatmapEntities() < 1) //bruh really you forgot to ckeck tempo changes
return;
if (!Conductor.instance.isPlaying)
@ -433,44 +429,52 @@ namespace HeavenStudio
#region Play Events
public void Play(float beat)
public void Play(float beat, float delay = 0f)
{
bool paused = Conductor.instance.isPaused;
Debug.Log("Playing at " + beat);
canInput = true;
inputOffsetSamples.Clear();
averageInputOffset = 0;
if (!paused)
{
inputOffsetSamples.Clear();
averageInputOffset = 0;
totalInputs = 0;
totalPlayerAccuracy = 0;
totalInputs = 0;
totalPlayerAccuracy = 0;
TimingAccuracyDisplay.instance.ResetArrow();
SkillStarManager.instance.Reset();
skillStarCollected = false;
TimingAccuracyDisplay.instance.ResetArrow();
SkillStarManager.instance.Reset();
skillStarCollected = false;
GoForAPerfect.instance.perfect = true;
GoForAPerfect.instance.Disable();
GoForAPerfect.instance.perfect = true;
GoForAPerfect.instance.Disable();
SectionMedalsManager.instance.Reset();
SectionMedalsManager.instance.Reset();
clearedSections.Clear();
}
StartCoroutine(PlayCo(beat));
StartCoroutine(PlayCo(beat, delay));
onBeatChanged?.Invoke(beat);
}
private IEnumerator PlayCo(float beat)
private IEnumerator PlayCo(float beat, float delay = 0f)
{
yield return null;
yield return new WaitForSeconds(delay);
bool paused = Conductor.instance.isPaused;
Conductor.instance.SetBpm(Beatmap.bpm);
Conductor.instance.SetVolume(Beatmap.musicVolume);
Conductor.instance.firstBeatOffset = Beatmap.firstBeatOffset;
Conductor.instance.Play(beat);
if (!paused)
if (paused)
{
SetCurrentEventToClosest(beat);
Util.Jukebox.UnpauseOneShots();
}
else
{
Conductor.instance.SetBpm(Beatmap.bpm);
Conductor.instance.SetVolume(Beatmap.musicVolume);
Conductor.instance.firstBeatOffset = Beatmap.firstBeatOffset;
SetCurrentEventToClosest(beat);
KillAllSounds();
}
KillAllSounds();
Minigame miniGame = currentGameO.GetComponent<Minigame>();
if (miniGame != null)
@ -480,11 +484,16 @@ namespace HeavenStudio
public void Pause()
{
Conductor.instance.Pause();
KillAllSounds();
Util.Jukebox.PauseOneShots();
canInput = false;
}
public void Stop(float beat)
public void Stop(float beat, bool restart = false, float restartDelay = 0f)
{
Minigame miniGame = currentGameO.GetComponent<Minigame>();
if (miniGame != null)
miniGame.OnStop(beat);
Conductor.instance.Stop(beat);
SetCurrentEventToClosest(beat);
onBeatChanged?.Invoke(beat);
@ -496,13 +505,40 @@ namespace HeavenStudio
GoForAPerfect.instance.Disable();
SectionMedalsManager.instance.OnRemixEnd();
// pass this data to rating screen + stats
Debug.Log($"== Playthrough statistics of {Beatmap["remixtitle"]} (played at {System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}) ==");
Debug.Log($"Average input offset for playthrough: {averageInputOffset}ms");
Debug.Log($"Accuracy for playthrough: {(PlayerAccuracy * 100) : 0.00}");
if (playOnStart)
Debug.Log($"Cleared {clearedSections.FindAll(c => c).Count} sections out of {Beatmap.beatmapSections.Count}");
if (SkillStarManager.instance.IsCollected)
Debug.Log($"Skill Star collected");
else
Debug.Log($"Skill Star not collected");
if (GoForAPerfect.instance.perfect)
Debug.Log($"Perfect Clear!");
if (playOnStart || restart)
{
Play(0);
Play(0, restartDelay);
}
// when rating screen gets added playOnStart will instead move to that scene
}
private IEnumerator WaitReadyAndPlayCo(float beat)
{
// wait for overlays to be ready
yield return new WaitUntil(() => OverlaysManager.OverlaysReady);
// wait for first game to be loaded
yield return new WaitUntil(() => Beatmap != null && Beatmap.entities.Count > 0);
SkillStarManager.instance.KillStar();
TimingAccuracyDisplay.instance.StopStarFlash();
GoForAPerfect.instance.Disable();
SectionMedalsManager.instance?.OnRemixEnd();
GlobalGameManager.UpdateDiscordStatus(Beatmap["remixtitle"], false, true);
Play(beat, 1f);
}
public void KillAllSounds()
@ -671,7 +707,7 @@ namespace HeavenStudio
{
if(flash == true)
{
this.GetComponent<SpriteRenderer>().enabled = true;
HeavenStudio.StaticCamera.instance.ToggleCanvasVisibility(false);
}
SetGame(game);
@ -680,9 +716,10 @@ namespace HeavenStudio
if (miniGame != null)
miniGame.OnGameSwitch(beat);
//TODO: wait time in beats instead of seconds
yield return new WaitForSeconds(0.1f);
this.GetComponent<SpriteRenderer>().enabled = false;
HeavenStudio.StaticCamera.instance.ToggleCanvasVisibility(true);
}
private void SetGame(string game)

View File

@ -8,7 +8,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_BlueBear
{
public class Treat : PlayerActionObject
public class Treat : MonoBehaviour
{
const float rotSpeed = 360f;

View File

@ -6,7 +6,7 @@ using System;
namespace HeavenStudio.Games.Scripts_BuiltToScaleDS
{
using HeavenStudio.Util;
public class Blocks : PlayerActionObject
public class Blocks : MonoBehaviour
{
public float createBeat;
public float createLength;

View File

@ -7,7 +7,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_CatchyTune
{
public class Fruit : PlayerActionObject
public class Fruit : MonoBehaviour
{
public bool isPineapple;

View File

@ -6,7 +6,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_ClappyTrio
{
public class ClappyTrioPlayer : PlayerActionObject
public class ClappyTrioPlayer : MonoBehaviour
{
ClappyTrio game;
private float lastClapBeat;

View File

@ -6,7 +6,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_CropStomp
{
public class Farmer : PlayerActionObject
public class Farmer : MonoBehaviour
{
public float nextStompBeat;

View File

@ -8,7 +8,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_CropStomp
{
public class Veggie : PlayerActionObject
public class Veggie : MonoBehaviour
{
static float pickedRotationSpeed = -1080f;

View File

@ -9,7 +9,7 @@ using Starpelly;
namespace HeavenStudio.Games.Scripts_DJSchool
{
public class Student : PlayerActionObject
public class Student : MonoBehaviour
{
public Animator anim;
public static bool soundFX;

View File

@ -8,7 +8,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_DogNinja
{
public class SpawnHalves : PlayerActionObject
public class SpawnHalves : MonoBehaviour
{
public float startBeat;
public Vector3 objPos;

View File

@ -8,7 +8,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_DogNinja
{
public class ThrowObject : PlayerActionObject
public class ThrowObject : MonoBehaviour
{
public float startBeat;
public int type;

View File

@ -6,7 +6,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_DrummingPractice
{
public class DrummerHit : PlayerActionObject
public class DrummerHit : MonoBehaviour
{
DrummingPractice game;
public float startBeat;

View File

@ -9,7 +9,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_FanClub
{
public class NtrIdolFan : PlayerActionObject
public class NtrIdolFan : MonoBehaviour
{
[Header("References")]
[SerializeField] private GameObject motionRoot;

View File

@ -6,7 +6,7 @@ using NaughtyBezierCurves;
namespace HeavenStudio.Games.Scripts_Fireworks
{
public class FireworksBomb : PlayerActionObject
public class FireworksBomb : MonoBehaviour
{
public BezierCurve3D curve;
public bool applause;

View File

@ -6,7 +6,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_Fireworks
{
public class Rocket : PlayerActionObject
public class Rocket : MonoBehaviour
{
[SerializeField] ParticleSystem particleBarelyEffect;
[SerializeField] private List<ParticleSystem> particleEffects = new List<ParticleSystem>();

View File

@ -8,7 +8,7 @@ using Starpelly;
namespace HeavenStudio.Games.Scripts_FirstContact
{
public class Translator : PlayerActionObject
public class Translator : MonoBehaviour
{
public Animator anim;

View File

@ -8,7 +8,7 @@ using DG.Tweening;
namespace HeavenStudio.Games.Scripts_ForkLifter
{
public class Pea : PlayerActionObject
public class Pea : MonoBehaviour
{
ForkLifter game;
private Animator anim;

View File

@ -5,7 +5,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_GleeClub
{
public class GleeClubSingInput : PlayerActionObject
public class GleeClubSingInput : MonoBehaviour
{
public float pitch = 1f;
bool shouldClose = true;

View File

@ -1,6 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using HeavenStudio.Util;
using System.Linq;
@ -9,49 +11,40 @@ namespace HeavenStudio.Games.Global
{
public class Flash : MonoBehaviour
{
public float startBeat;
public float length;
[NonSerialized] public float startBeat;
[NonSerialized] public float length;
public Color startColor;
public Color endColor;
[NonSerialized] public Color startColor;
[NonSerialized] public Color endColor;
public EasingFunction.Ease ease;
private EasingFunction.Function func;
[NonSerialized] public EasingFunction.Ease ease;
[NonSerialized] private EasingFunction.Function func;
private SpriteRenderer spriteRenderer;
[NonSerialized] private Image spriteRenderer;
[SerializeField] private Color currentCol;
private List<DynamicBeatmap.DynamicEntity> allFadeEvents = new List<DynamicBeatmap.DynamicEntity>();
[NonSerialized] private List<DynamicBeatmap.DynamicEntity> allFadeEvents = new List<DynamicBeatmap.DynamicEntity>();
private void Awake()
{
this.gameObject.transform.SetParent(GameManager.instance.gameObject.transform);
gameObject.layer = LayerMask.NameToLayer("Flash");
this.gameObject.transform.localScale = new Vector3(1, 1);
spriteRenderer = this.gameObject.AddComponent<SpriteRenderer>();
spriteRenderer.color = startColor;
spriteRenderer.sortingOrder = 30001;
spriteRenderer.sprite = Resources.Load<Sprite>("Sprites/GeneralPurpose/Square");
spriteRenderer = GetComponent<Image>();
spriteRenderer.color = currentCol;
func = EasingFunction.GetEasingFunction(EasingFunction.Ease.Linear);
GameManager.instance.onBeatChanged += OnBeatChanged;
}
public void OnBeatChanged(float beat)
{
allFadeEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "flash" });
Test(beat);
// backwards-compatibility baybee
allFadeEvents.AddRange(EventCaller.GetAllInGameManagerList("gameManager", new string[] { "flash" }));
Test(beat);
allFadeEvents.Sort((x, y) => x.beat.CompareTo(y.beat));
FindFadeFromBeat(beat);
}
private void Test(float beat)
private void FindFadeFromBeat(float beat)
{
Color startCol = Color.white;
Color endCol = Color.white;
@ -105,7 +98,7 @@ namespace HeavenStudio.Games.Global
private void Update()
{
Test(Conductor.instance.songPositionInBeats);
FindFadeFromBeat(Conductor.instance.songPositionInBeats);
float normalizedBeat = Conductor.instance.GetPositionFromBeat(startBeat, length);
// normalizedBeat = Mathf.Clamp01(normalizedBeat);

View File

@ -32,7 +32,7 @@ namespace HeavenStudio.Games.Global
private List<DynamicBeatmap.DynamicEntity> idolEvents = new List<DynamicBeatmap.DynamicEntity>();
private List<DynamicBeatmap.DynamicEntity> closedCaptionsEvents = new List<DynamicBeatmap.DynamicEntity>();
Textbox instance;
public static Textbox instance { get; private set; }
[Header("Objects")]
public GameObject TextboxEnabler;

View File

@ -8,7 +8,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_KarateMan
{
public class KarateManPot : PlayerActionObject
public class KarateManPot : MonoBehaviour
{
public float startBeat;
public ItemType type;

View File

@ -11,7 +11,7 @@ using static HeavenStudio.EntityTypes;
namespace HeavenStudio.Games.Scripts_LaunchParty
{
public class LaunchPartyRocket : PlayerActionObject
public class LaunchPartyRocket : MonoBehaviour
{
public List<float> pitches = new List<float>();
[SerializeField] Animator anim;

View File

@ -6,7 +6,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_MarchingOrders
{
public class Cadet : PlayerActionObject
public class Cadet : MonoBehaviour
{
public bool isSparkler;

View File

@ -7,7 +7,7 @@ using NaughtyBezierCurves;
namespace HeavenStudio.Games.Scripts_MeatGrinder
{
public class MeatToss : PlayerActionObject
public class MeatToss : MonoBehaviour
{
public float startBeat;
public float cueLength;

View File

@ -120,7 +120,7 @@ namespace HeavenStudio.Games
if(closest == null)
{
if (input == InputType.ANY || toCompare.inputType.HasFlag(input))
if (input == InputType.ANY || (toCompare.inputType & input) != 0)
closest = toCompare;
} else
{
@ -131,7 +131,7 @@ namespace HeavenStudio.Games
if (t2 < t1)
{
if (input == InputType.ANY || toCompare.inputType.HasFlag(input))
if (input == InputType.ANY || (toCompare.inputType & input) != 0)
closest = toCompare;
}
}
@ -220,6 +220,14 @@ namespace HeavenStudio.Games
}
public virtual void OnStop(float beat)
{
foreach (var evt in scheduledInputs)
{
evt.Disable();
}
}
public int MultipleEventsAtOnce()
{
int sameTime = 0;

View File

@ -7,7 +7,7 @@ using NaughtyBezierCurves;
namespace HeavenStudio.Games.Scripts_MunchyMonk
{
public class Dumpling : PlayerActionObject
public class Dumpling : MonoBehaviour
{
public Animator otherAnim;
public float startBeat;

View File

@ -1,3 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
@ -11,8 +12,9 @@ using HeavenStudio.Common;
namespace HeavenStudio.Games
{
public class PlayerActionEvent : PlayerActionObject
public class PlayerActionEvent : MonoBehaviour
{
static List<PlayerActionEvent> allEvents = new List<PlayerActionEvent>();
public static bool EnableAutoplayCheat = true;
public delegate void ActionEventCallback(PlayerActionEvent caller);
public delegate void ActionEventCallbackState(PlayerActionEvent caller, float state);
@ -26,8 +28,12 @@ namespace HeavenStudio.Games
public float startBeat;
public float timer;
public bool isEligible = true;
public bool canHit = true; //Indicates if you can still hit the cue or not. If set to false, it'll guarantee a miss
public bool enabled = true; //Indicates if the PlayerActionEvent is enabled. If set to false, it'll not trigger any events and destroy itself AFTER it's not relevant anymore
public bool triggersAutoplay = true;
bool lockedByEvent = false;
bool markForDeletion = false;
public bool autoplayOnly = false; //Indicates if the input event only triggers when it's autoplay. If set to true, NO Miss or Blank events will be triggered when you're not autoplaying.
@ -51,43 +57,72 @@ namespace HeavenStudio.Games
public void Enable() { enabled = true; }
public void Disable() { enabled = false; }
public void QueueDeletion() { markForDeletion = true; }
public bool IsCorrectInput() =>
//General inputs, both down and up
(PlayerInput.Pressed() && inputType.HasFlag(InputType.STANDARD_DOWN)) ||
(PlayerInput.AltPressed() && inputType.HasFlag(InputType.STANDARD_ALT_DOWN)) ||
(PlayerInput.GetAnyDirectionDown() && inputType.HasFlag(InputType.DIRECTION_DOWN)) ||
(PlayerInput.PressedUp() && inputType.HasFlag(InputType.STANDARD_UP)) ||
(PlayerInput.AltPressedUp() && inputType.HasFlag(InputType.STANDARD_ALT_UP)) ||
(PlayerInput.GetAnyDirectionUp() && inputType.HasFlag(InputType.DIRECTION_UP)) ||
//Specific directional inputs
(PlayerInput.GetSpecificDirectionDown(PlayerInput.DOWN) && inputType.HasFlag(InputType.DIRECTION_DOWN_DOWN)) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.UP) && inputType.HasFlag(InputType.DIRECTION_UP_DOWN)) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.LEFT) && inputType.HasFlag(InputType.DIRECTION_LEFT_DOWN)) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.RIGHT) && inputType.HasFlag(InputType.DIRECTION_RIGHT_DOWN)) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.DOWN) && inputType.HasFlag(InputType.DIRECTION_DOWN_UP)) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.UP) && inputType.HasFlag(InputType.DIRECTION_UP_UP)) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.LEFT) && inputType.HasFlag(InputType.DIRECTION_LEFT_UP)) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.RIGHT) && inputType.HasFlag(InputType.DIRECTION_RIGHT_UP));
public void CanHit(bool canHit)
{
this.canHit = canHit;
}
public void Start()
{
allEvents.Add(this);
}
public void Update()
{
if(!Conductor.instance.NotStopped()){CleanUp();} // If the song is stopped entirely in the editor, destroy itself as we don't want duplicates
if (markForDeletion) CleanUp();
if(!Conductor.instance.NotStopped()) CleanUp(); // If the song is stopped entirely in the editor, destroy itself as we don't want duplicates
if (noAutoplay && autoplayOnly) autoplayOnly = false;
if (noAutoplay && triggersAutoplay){ triggersAutoplay = false; }
if (noAutoplay && triggersAutoplay) triggersAutoplay = false;
if (!enabled) return;
double normalizedTime = GetNormalizedTime();
double stateProg = ((normalizedTime - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2;
StateCheck(normalizedTime);
if (GameManager.instance.autoplay)
{
AutoplayInput(normalizedTime);
return;
}
//BUGFIX: ActionEvents destroyed too early
if (normalizedTime > Minigame.EndTime()) Miss();
if (IsCorrectInput() && !autoplayOnly)
if (lockedByEvent)
{
if (state.perfect)
return;
}
if (!CheckEventLock())
{
return;
}
if (!autoplayOnly && IsCorrectInput())
{
if (IsExpectingInputNow())
{
double stateProg = ((normalizedTime - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2;
Hit(stateProg, normalizedTime);
}
else if (state.early && !perfectOnly)
{
Hit(-1f, normalizedTime);
}
else if (state.late && !perfectOnly)
{
Hit(1f, normalizedTime);
}
else
{
Blank();
@ -95,6 +130,60 @@ namespace HeavenStudio.Games
}
}
public void LateUpdate() {
if (markForDeletion) {
CleanUp();
Destroy(this.gameObject);
}
foreach (PlayerActionEvent evt in allEvents)
{
evt.lockedByEvent = false;
}
}
private bool CheckEventLock()
{
foreach(PlayerActionEvent toCompare in allEvents)
{
if (toCompare == this) continue;
if (toCompare.autoplayOnly) continue;
if ((toCompare.inputType & this.inputType) == 0) continue;
if (!toCompare.IsExpectingInputNow()) continue;
double t1 = this.startBeat + this.timer;
double t2 = toCompare.startBeat + toCompare.timer;
double songPos = Conductor.instance.songPositionInBeatsAsDouble;
// compare distance between current time and the events
// events that happen at the exact same time with the exact same inputs will return true
if (Math.Abs(t1 - songPos) > Math.Abs(t2 - songPos))
return false;
else if (t1 != t2) // if they are the same time, we don't want to lock the event
toCompare.lockedByEvent = true;
}
return true;
}
private void AutoplayInput(double normalizedTime, bool autoPlay = false)
{
if (triggersAutoplay && (GameManager.instance.autoplay || autoPlay) && GameManager.instance.canInput && normalizedTime >= 1f - (Time.deltaTime*0.5f))
{
AutoplayEvent();
if (!autoPlay)
TimelineAutoplay();
}
}
// TODO: move this to timeline code instead
private void TimelineAutoplay()
{
if (Editor.Editor.instance == null) return;
if (Editor.Track.Timeline.instance != null && !Editor.Editor.instance.fullscreen)
{
Editor.Track.Timeline.instance.AutoplayBTN.GetComponent<Animator>().Play("Ace", 0, 0);
}
}
public bool IsExpectingInputNow()
{
double normalizedBeat = GetNormalizedTime();
@ -104,41 +193,15 @@ namespace HeavenStudio.Games
double GetNormalizedTime()
{
var cond = Conductor.instance;
double currTime = cond.GetSongPosFromBeat(cond.songPositionInBeatsAsDouble);
double currTime = cond.songPositionAsDouble;
double targetTime = cond.GetSongPosFromBeat(startBeat + timer);
double min = targetTime - 1f;
double max = targetTime + 1f;
return 1f + (((currTime - min) / (max - min))-0.5f)*2;
}
public bool IsCorrectInput()
{
// This one is a mouthful but it's an evil good to detect the correct input
// Forgive me for those input type names
return (
//General inputs, both down and up
(PlayerInput.Pressed() && inputType.HasFlag(InputType.STANDARD_DOWN)) ||
(PlayerInput.AltPressed() && inputType.HasFlag(InputType.STANDARD_ALT_DOWN)) ||
(PlayerInput.GetAnyDirectionDown() && inputType.HasFlag(InputType.DIRECTION_DOWN)) ||
(PlayerInput.PressedUp() && inputType.HasFlag(InputType.STANDARD_UP)) ||
(PlayerInput.AltPressedUp() && inputType.HasFlag(InputType.STANDARD_ALT_UP)) ||
(PlayerInput.GetAnyDirectionUp() && inputType.HasFlag(InputType.DIRECTION_UP)) ||
//Specific directional inputs
(PlayerInput.GetSpecificDirectionDown(PlayerInput.DOWN) && inputType.HasFlag(InputType.DIRECTION_DOWN_DOWN)) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.UP) && inputType.HasFlag(InputType.DIRECTION_UP_DOWN)) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.LEFT) && inputType.HasFlag(InputType.DIRECTION_LEFT_DOWN)) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.RIGHT) && inputType.HasFlag(InputType.DIRECTION_RIGHT_DOWN)) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.DOWN) && inputType.HasFlag(InputType.DIRECTION_DOWN_UP)) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.UP) && inputType.HasFlag(InputType.DIRECTION_UP_UP)) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.LEFT) && inputType.HasFlag(InputType.DIRECTION_LEFT_UP)) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.RIGHT) && inputType.HasFlag(InputType.DIRECTION_RIGHT_UP))
);
}
//For the Autoplay
public override void OnAce()
public void AutoplayEvent()
{
if (EnableAutoplayCheat)
{
@ -162,6 +225,7 @@ namespace HeavenStudio.Games
double normalized = time - 1f;
int offset = Mathf.CeilToInt((float)normalized * 1000);
GameManager.instance.AvgInputOffset = offset;
state = System.Math.Max(-1.0, System.Math.Min(1.0, state));
OnHit(this, (float) state);
CleanUp();
@ -256,9 +320,10 @@ namespace HeavenStudio.Games
public void CleanUp()
{
if (markForDeletion) return;
allEvents.Remove(this);
OnDestroy(this);
Destroy(this.gameObject);
markForDeletion = true;
}
}
}

View File

@ -1,169 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Editor;
using HeavenStudio.Editor.Track;
namespace HeavenStudio.Games
{
public class PlayerActionObject : MonoBehaviour
{
public bool inList = false;
public Minigame.Eligible state = new Minigame.Eligible();
public List<Minigame.Eligible> eligibleHitsList = new List<Minigame.Eligible>();
//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 = true;
private bool autoPlayEnabledOnStart; //value never used for anything
public bool triggersAutoplay = true;
public void PlayerActionInit(GameObject g, float createBeat)
{
state.gameObject = g;
state.createBeat = createBeat;
autoPlayEnabledOnStart = GameManager.instance.autoplay;
}
private void CheckForAce(double normalizedBeat, bool autoPlay = false)
{
if (aceTimes == 0)
{
if (triggersAutoplay && (GameManager.instance.autoplay || autoPlay) && GameManager.instance.canInput && normalizedBeat >= 1f - (Time.deltaTime*0.5f))
{
OnAce();
if (!autoPlay)
AceVisuals();
// aceTimes++;
}
}
}
public void ResetAce()
{
aceTimes = 0;
}
public void ResetState()
{
ResetAce();
}
// could possibly add support for custom early, perfect, and end times if needed.
public void StateCheck(double normalizedBeat, bool autoPlay = false)
{
CheckForAce(normalizedBeat, autoPlay);
if (normalizedBeat > Minigame.EarlyTime() && normalizedBeat < Minigame.PerfectTime())
{
MakeEligible(true, false, false);
}
// Perfect State
else if (normalizedBeat > Minigame.PerfectTime() && normalizedBeat < Minigame.LateTime())
{
MakeEligible(false, true, false);
}
// Late State
else if (normalizedBeat > Minigame.LateTime() && normalizedBeat < Minigame.EndTime())
{
MakeEligible(false, false, true);
}
else if (normalizedBeat < Minigame.EarlyTime() || normalizedBeat > Minigame.EndTime())
{
MakeInEligible();
}
}
public void MakeEligible(bool early, bool perfect, bool late)
{
if (!inList)
{
state.early = early;
state.perfect = perfect;
state.late = late;
eligibleHitsList.Add(state);
inList = true;
}
else
{
Minigame.Eligible es = eligibleHitsList[eligibleHitsList.IndexOf(state)];
es.early = early;
es.perfect = perfect;
es.late = late;
}
}
public void MakeInEligible()
{
state.early = false;
state.perfect = false;
state.late = false;
if (!inList) return;
eligibleHitsList.Remove(state);
inList = false;
}
public void RemoveObject(int currentHitInList, bool destroyObject = false)
{
if (currentHitInList < eligibleHitsList.Count)
{
eligibleHitsList.Remove(eligibleHitsList[currentHitInList]);
currentHitInList++;
if (destroyObject) Destroy(this.gameObject);
}
}
// No list
public void StateCheckNoList(float normalizedBeat)
{
CheckForAce(normalizedBeat);
if (normalizedBeat > Minigame.EarlyTime() && normalizedBeat < Minigame.PerfectTime())
{
ModifyState(true, false, false);
}
// Perfect State
else if (normalizedBeat > Minigame.PerfectTime() && normalizedBeat < Minigame.LateTime())
{
ModifyState(false, true, false);
}
// Late State
else if (normalizedBeat > Minigame.LateTime() && normalizedBeat < Minigame.EndTime())
{
ModifyState(false, false, true);
}
else if (normalizedBeat < Minigame.EarlyTime() || normalizedBeat > Minigame.EndTime())
{
// ineligible
}
}
public virtual void OnAce()
{
}
private void AceVisuals()
{
if (Timeline.instance != null && Editor.Editor.instance != null && !Editor.Editor.instance.fullscreen)
{
Timeline.instance.AutoplayBTN.GetComponent<Animator>().Play("Ace", 0, 0);
}
}
private void ModifyState(bool early, bool perfect, bool late)
{
state.early = early;
state.perfect = perfect;
state.late = late;
}
private void OnDestroy()
{
MakeInEligible();
}
}
}

View File

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

View File

@ -8,7 +8,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_RhythmRally
{
public class Paddlers : PlayerActionObject
public class Paddlers : MonoBehaviour
{
private RhythmRally game;
private Animator playerAnim;

View File

@ -5,7 +5,7 @@ using System;
namespace HeavenStudio.Games.Scripts_RhythmTweezers
{
public class Hair : PlayerActionObject
public class Hair : MonoBehaviour
{
public float createBeat;
public GameObject hairSprite;

View File

@ -6,7 +6,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_RhythmTweezers
{
public class LongHair : PlayerActionObject
public class LongHair : MonoBehaviour
{
public float createBeat;
public GameObject hairSprite;
@ -44,7 +44,7 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
if (endInput == InputType.DIRECTION_UP) input = PlayerInput.GetAnyDirectionUp();
if (input && !game.IsExpectingInputNow(endInput))
{
endEvent.MakeInEligible();
endEvent.isEligible = false;
EndEarly();
return;
}

View File

@ -4,7 +4,7 @@ using UnityEngine;
using HeavenStudio.Util;
namespace HeavenStudio
namespace HeavenStudio.Games
{
public class SoundEffects : MonoBehaviour
{

View File

@ -6,7 +6,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_SpaceSoccer
{
public class Kicker : PlayerActionObject
public class Kicker : MonoBehaviour
{
SpaceSoccer game;
@ -82,7 +82,6 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer
public void Kick(bool hit, bool highKick = false)
{
if (stopBall) return;
aceTimes = 0;
if (player)
{

View File

@ -9,7 +9,7 @@ using NaughtyBezierCurves;
namespace HeavenStudio.Games.Scripts_Spaceball
{
public class SpaceballBall : PlayerActionObject
public class SpaceballBall : MonoBehaviour
{
#region Public
@ -46,8 +46,6 @@ namespace HeavenStudio.Games.Scripts_Spaceball
e.gameObject = this.gameObject;
startRot = Random.Range(0, 360);
isEligible = true;
}
private void Start()

View File

@ -1,61 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_TapTrial
{
public class Tap : PlayerActionObject
{
public float startBeat;
public int type;
void Awake()
{
PlayerActionInit(this.gameObject, startBeat);
}
public override void OnAce()
{
Hit(true);
}
// Update is called once per frame
void Update()
{
if (Conductor.instance.GetPositionFromBeat(startBeat, 2) >= 1)
CleanUp();
float normalizedBeat = Conductor.instance.GetPositionFromBeat(startBeat, 1f);
StateCheck(normalizedBeat);
if(PlayerInput.Pressed())
{
if(state.perfect)
{
Hit(true);
}
else if(state.notPerfect())
{
Hit(false);
}
}
}
public void Hit(bool hit)
{
TapTrial.instance.player.Tap(hit, type);
if (hit)
CleanUp();
}
public void CleanUp()
{
Destroy(this.gameObject);
}
}
}

View File

@ -8,7 +8,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_TrickClass
{
public class MobTrickObj : PlayerActionObject
public class MobTrickObj : MonoBehaviour
{
public bool flyType;
public float startBeat;

View File

@ -5,7 +5,7 @@ using System;
namespace HeavenStudio.Games.Scripts_WizardsWaltz
{
public class Plant : PlayerActionObject
public class Plant : MonoBehaviour
{
public Animator animator;
public SpriteRenderer spriteRenderer;

View File

@ -7,7 +7,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_WorkingDough
{
public class BGBall : PlayerActionObject
public class BGBall : MonoBehaviour
{
public float startBeat;
public float firstBeatsToTravel = 3f;

View File

@ -14,7 +14,7 @@ namespace HeavenStudio.Games.Scripts_WorkingDough
ExitingUp = 2,
ExitingDown = 3
}
public class NPCDoughBall : PlayerActionObject
public class NPCDoughBall : MonoBehaviour
{
public float startBeat;

View File

@ -7,7 +7,7 @@ using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_WorkingDough
{
public class PlayerEnterDoughBall : PlayerActionObject
public class PlayerEnterDoughBall : MonoBehaviour
{
public float startBeat;
public float firstBeatsToTravel = 0.5f;

View File

@ -1,9 +1,11 @@
using System.Collections;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using DG.Tweening;
using TMPro;
using HeavenStudio.Common;
@ -12,19 +14,22 @@ namespace HeavenStudio
public class GlobalGameManager : MonoBehaviour
{
public static GlobalGameManager instance { get; set; }
[SerializeField] Image fadeImage;
[SerializeField] TMP_Text loadingText;
public static string buildTime = "00/00/0000 00:00:00";
public static int loadedScene;
public int lastLoadedScene;
public static float fadeDuration;
public static bool discordDuringTesting = false;
public GameObject loadScenePrefab;
public GameObject hourGlass;
static string loadedScene;
static string lastLoadedScene;
static AsyncOperation asyncLoad;
public static string levelLocation;
public static bool officialLevel;
public static bool IsFirstBoot = false;
public static int CustomScreenWidth = 1280;
public static int CustomScreenHeight = 720;
@ -56,13 +61,12 @@ namespace HeavenStudio
Game = 3
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void Init()
{
BasicCheck();
loadedScene = 0;
fadeDuration = 0;
loadedScene = SceneManager.GetActiveScene().name;
PersistentDataManager.LoadSettings();
@ -91,13 +95,6 @@ namespace HeavenStudio
Screen.fullScreen = false;
ChangeScreenSize();
}
}
public void Awake()
{
Init();
DontDestroyOnLoad(this.gameObject);
instance = this;
QualitySettings.maxQueuedFrames = 1;
PlayerInput.InitInputControllers();
#if UNITY_EDITOR
@ -106,59 +103,100 @@ namespace HeavenStudio
#else
Starpelly.OS.ChangeWindowTitle("Heaven Studio (INDEV) " + Application.buildGUID.Substring(0, 8));
buildTime = Application.buildGUID.Substring(0, 8) + " " + AppInfo.Date.ToString("dd/MM/yyyy hh:mm:ss");
#endif
#endif
}
// todo: make this part of the camera prefab instead of generated in code
public static GameObject CreateFade()
public void Awake()
{
GameObject fade = new GameObject();
DontDestroyOnLoad(fade);
fade.transform.localScale = new Vector3(4000, 4000);
SpriteRenderer sr = fade.AddComponent<SpriteRenderer>();
sr.sprite = Resources.Load<Sprite>("Sprites/GeneralPurpose/Square");
sr.sortingOrder = 20000;
fade.layer = 5;
return fade;
DontDestroyOnLoad(this.gameObject);
instance = this;
fadeImage.gameObject.SetActive(false);
loadingText.enabled = false;
}
private void Update()
{
PlayerInput.UpdateInputControllers();
}
IEnumerator LoadSceneAsync(string scene, float fadeOut)
{
//TODO: create flow mem loading icon
asyncLoad = SceneManager.LoadSceneAsync(scene);
while (!asyncLoad.isDone)
{
yield return null;
}
//TODO: fade out flow mem loading icon
instance.fadeImage.DOKill();
instance.loadingText.enabled = false;
instance.fadeImage.DOFade(0, fadeOut).OnComplete(() =>
{
instance.fadeImage.gameObject.SetActive(false);
});
}
IEnumerator ForceFadeAsync(float hold, float fadeOut)
{
yield return new WaitForSeconds(hold);
instance.fadeImage.DOKill();
instance.loadingText.enabled = false;
instance.fadeImage.DOFade(0, fadeOut).OnComplete(() =>
{
instance.fadeImage.gameObject.SetActive(false);
});
}
public static void BasicCheck()
{
if (FindGGM() == null)
{
GameObject GlobalGameManager = new GameObject("GlobalGameManager");
GlobalGameManager.name = "GlobalGameManager";
GlobalGameManager.AddComponent<GlobalGameManager>();
// load the global game manager prefab
GameObject ggm = Instantiate(Resources.Load("Prefabs/GlobalGameManager") as GameObject);
DontDestroyOnLoad(ggm);
}
}
public static GameObject FindGGM()
{
if (GameObject.Find("GlobalGameManager") != null)
return GameObject.Find("GlobalGameManager");
if (instance != null)
return instance.gameObject;
else
return null;
}
public static void LoadScene(int sceneIndex, float duration = 0.35f)
public static void LoadScene(string scene, float fadeIn = 0.35f, float fadeOut = 0.35f)
{
print("bruh");
BasicCheck();
loadedScene = sceneIndex;
fadeDuration = duration;
if (scene == loadedScene)
return;
lastLoadedScene = loadedScene;
loadedScene = scene;
// DOTween.Clear(true);
// SceneManager.LoadScene(sceneIndex);
instance.fadeImage.DOKill();
instance.fadeImage.gameObject.SetActive(true);
instance.fadeImage.color = new Color(0, 0, 0, 0);
instance.fadeImage.DOFade(1, fadeIn).OnComplete(() =>
{
instance.StartCoroutine(instance.LoadSceneAsync(scene, fadeOut));
instance.loadingText.enabled = true;
});
}
GameObject fade = CreateFade();
fade.GetComponent<SpriteRenderer>().color = new Color(0, 0, 0, 0);
fade.GetComponent<SpriteRenderer>().DOColor(Color.black, fadeDuration).OnComplete(() => { SceneManager.LoadScene(loadedScene); fade.GetComponent<SpriteRenderer>().DOColor(new Color(0, 0, 0, 0), fadeDuration).OnComplete(() => { Destroy(fade); }); });
public static void ForceFade(float fadeIn, float hold, float fadeOut)
{
instance.fadeImage.DOKill();
instance.fadeImage.gameObject.SetActive(true);
instance.fadeImage.color = new Color(0, 0, 0, 0);
instance.loadingText.enabled = false;
instance.fadeImage.DOFade(1, fadeIn).OnComplete(() =>
{
instance.StartCoroutine(instance.ForceFadeAsync(hold, fadeOut));
});
}
public static void WindowFullScreen()
{
Debug.Log("WindowFullScreen");
if (!Screen.fullScreen)
{
// Set the resolution to the display's current resolution
@ -236,6 +274,18 @@ namespace HeavenStudio
PersistentDataManager.gameSettings.sampleRate = currentSampleRate;
}
public static void UpdateDiscordStatus(string details, bool editor = false, bool updateTime = false)
{
if (discordDuringTesting || !Application.isEditor)
{
if (PersistentDataManager.gameSettings.discordRPCEnable)
{
DiscordRPC.DiscordRPC.UpdateActivity(editor ? "In Editor " : "Playing ", details, updateTime);
Debug.Log("Discord status updated");
}
}
}
void OnApplicationQuit()
{
Debug.Log("Disconnecting JoyShocks...");

View File

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

View File

@ -24,7 +24,7 @@ namespace HeavenStudio.InputSystem
KeyCode.U, // north face button
KeyCode.C, // left shoulder button
KeyCode.N, // right shoulder button
KeyCode.Return, // start button
KeyCode.Escape, // start button
};
InputDirection hatDirectionCurrent;

View File

@ -9,12 +9,14 @@ namespace HeavenStudio.Editor
{
public class Dialog : MonoBehaviour
{
public bool IsOpen { get { return dialog.activeSelf; } }
[SerializeField] protected GameObject dialog;
public void ForceState(bool onoff = false)
{
dialog.SetActive(onoff);
if (Editor.instance == null) return;
Editor.instance.canSelect = !onoff;
Editor.instance.inAuthorativeMenu = onoff;
dialog.SetActive(onoff);
}
public static void ResetAllDialogs()

View File

@ -25,7 +25,7 @@ namespace HeavenStudio.Editor
{
public class Editor : MonoBehaviour
{
private Initializer Initializer;
private GameInitializer Initializer;
[SerializeField] public Canvas MainCanvas;
[SerializeField] public Camera EditorCamera;
@ -85,7 +85,7 @@ namespace HeavenStudio.Editor
private void Start()
{
instance = this;
Initializer = GetComponent<Initializer>();
Initializer = GetComponent<GameInitializer>();
canSelect = true;
}
@ -517,13 +517,7 @@ namespace HeavenStudio.Editor
private void UpdateEditorStatus(bool updateTime)
{
if (discordDuringTesting || !Application.isEditor)
{
if (isDiscordEnabled)
{ DiscordRPC.DiscordRPC.UpdateActivity("In Editor", $"{remixName}", updateTime);
Debug.Log("Discord status updated");
}
}
GlobalGameManager.UpdateDiscordStatus($"{remixName}", true, updateTime);
}
public string GetJson()

View File

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

View File

@ -80,7 +80,6 @@ namespace HeavenStudio.Editor
{
currentEventIndex = amount;
EventRef.transform.parent.DOKill();
CurrentSelected.transform.DOKill();
if (currentEventIndex < 0)
@ -98,20 +97,36 @@ namespace HeavenStudio.Editor
{
selectorHeight = GameEventSelectorRect.rect.height;
eventSize = EventRef.GetComponent<RectTransform>().rect.height;
// EventRef.transform.parent.DOKill();
float lastLocalY = EventRef.transform.parent.transform.localPosition.y;
if (currentEventIndex * eventSize >= selectorHeight/2 && eventsParent.childCount * eventSize >= selectorHeight)
{
if (currentEventIndex * eventSize < eventsParent.childCount * eventSize - selectorHeight/2)
{
EventRef.transform.parent.DOLocalMoveY((currentEventIndex * eventSize) - selectorHeight/2, 0.35f).SetEase(Ease.OutExpo);
EventRef.transform.parent.transform.localPosition = new Vector3(
EventRef.transform.parent.transform.localPosition.x,
Mathf.Lerp(lastLocalY, (currentEventIndex * eventSize) - selectorHeight/2, 12 * Time.deltaTime),
EventRef.transform.parent.transform.localPosition.z
);
}
else
{
EventRef.transform.parent.DOLocalMoveY((eventsParent.childCount * eventSize) - selectorHeight + (eventSize*0.33f), 0.35f).SetEase(Ease.OutExpo);
EventRef.transform.parent.transform.localPosition = new Vector3(
EventRef.transform.parent.transform.localPosition.x,
Mathf.Lerp(lastLocalY, (eventsParent.childCount * eventSize) - selectorHeight + (eventSize*0.33f), 12 * Time.deltaTime),
EventRef.transform.parent.transform.localPosition.z
);
}
}
else
EventRef.transform.parent.DOLocalMoveY(0, 0.35f).SetEase(Ease.OutExpo);
{
EventRef.transform.parent.transform.localPosition = new Vector3(
EventRef.transform.parent.transform.localPosition.x,
Mathf.Lerp(lastLocalY, 0, 12 * Time.deltaTime),
EventRef.transform.parent.transform.localPosition.z
);
}
}
public void SelectGame(string gameName, int index)
@ -134,7 +149,7 @@ namespace HeavenStudio.Editor
currentEventIndex = 0;
UpdateIndex(0, false);
Editor.instance.SetGameEventTitle($"Select game event for {gameName.Replace("\n", "")}");
Editor.instance?.SetGameEventTitle($"Select game event for {gameName.Replace("\n", "")}");
}
private void AddEvents()

View File

@ -133,7 +133,18 @@ namespace HeavenStudio.Editor.Track
DynamicBeatmap.TempoChange tempoC = new DynamicBeatmap.TempoChange();
tempoC.beat = tempoChange.transform.localPosition.x;
tempoC.tempo = GameManager.instance.Beatmap.bpm;
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
{
tempoC.tempo = GameManager.instance.Beatmap.bpm * 2f;
}
else if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
{
tempoC.tempo = GameManager.instance.Beatmap.bpm / 2f;
}
else
{
tempoC.tempo = GameManager.instance.Beatmap.bpm;
}
tempoTimelineObj.tempoChange = tempoC;
GameManager.instance.Beatmap.tempoChanges.Add(tempoC);

View File

@ -0,0 +1,102 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using HeavenStudio.Common;
namespace HeavenStudio
{
public class OpeningManager : MonoBehaviour
{
[SerializeField] Animator openingAnim;
[SerializeField] TMP_Text buildText;
[SerializeField] TMP_Text versionDisclaimer;
public static string OnOpenFile;
bool fastBoot = false;
void Start()
{
string[] args = System.Environment.GetCommandLineArgs();
for (int i = 1; i < args.Length; i++)
{
// first arg is always this executable
Debug.Log(args[i]);
if (args[i].IndexOfAny(Path.GetInvalidPathChars()) == -1)
{
if (File.Exists(args[i]) && (args[i].EndsWith(".riq") || args[i].EndsWith(".tengoku")))
{
OnOpenFile = args[i];
}
}
if (args[i] == "--nosplash")
{
fastBoot = true;
}
}
#if UNITY_EDITOR
buildText.text = "EDITOR";
#else
buildText.text = Application.buildGUID.Substring(0, 8) + " " + AppInfo.Date.ToString("dd/MM/yyyy hh:mm:ss");
#endif
if (Application.platform is RuntimePlatform.OSXPlayer or RuntimePlatform.OSXEditor)
{
versionDisclaimer.text = "";
}
else
{
string ver = "<color=#FFFFCC>If you're coming from an older Heaven Studio build, copy your settings configs over from\n<color=#FFFF00>";
if (Application.platform is RuntimePlatform.WindowsPlayer or RuntimePlatform.WindowsEditor)
{
ver += Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\AppData\\LocalLow\\Megaminerzero\\Heaven Studio\\";
ver += "<color=#FFFFCC>\nto\n<color=#FFFF00>";
ver += Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\AppData\\LocalLow\\RHeavenStudio\\Heaven Studio\\";
}
else if (Application.platform is RuntimePlatform.LinuxPlayer or RuntimePlatform.LinuxEditor)
{
ver += "~/.config/unity3d/Megaminerzero/Heaven Studio/";
ver += "<color=#FFFFCC>\nto\n<color=#FFFF00>";
ver += "~/.config/unity3d/RHeavenStudio/Heaven Studio/";
}
versionDisclaimer.text = ver;
}
if (!GlobalGameManager.IsFirstBoot && !PersistentDataManager.gameSettings.showSplash)
{
fastBoot = true;
}
if (fastBoot)
{
OnFinishDisclaimer(0.1f);
}
else
{
openingAnim.Play("FirstOpening", -1, 0);
StartCoroutine(WaitAndFinishOpening());
}
}
IEnumerator WaitAndFinishOpening()
{
yield return new WaitForSeconds(8f);
OnFinishDisclaimer(0.35f);
}
void OnFinishDisclaimer(float fadeDuration = 0)
{
if (OnOpenFile is not null or "")
{
GlobalGameManager.LoadScene("Game", fadeDuration, 0.5f);
}
else
{
GlobalGameManager.LoadScene("Editor", fadeDuration, fadeDuration);
}
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 01f0b70cc14be2e47998a680099e7986
guid: 6282831a1c3a9d0429e232bbbe279a70
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -23,6 +23,7 @@ namespace HeavenStudio.Common
public static void CreateDefaultSettings()
{
gameSettings = new GameSettings(
true,
false,
1,
GlobalGameManager.DEFAULT_SCREEN_SIZES[1].width,
@ -70,6 +71,7 @@ namespace HeavenStudio.Common
}
else
{
GlobalGameManager.IsFirstBoot = true;
CreateDefaultSettings();
}
}
@ -96,6 +98,7 @@ namespace HeavenStudio.Common
{
// default settings constructor
public GameSettings(
bool showSplash = false,
bool isFullscreen = false,
int resolutionIndex = 0,
int resolutionWidth = 1280,
@ -113,6 +116,7 @@ namespace HeavenStudio.Common
bool letterboxFxEnable = true
)
{
this.showSplash = showSplash;
this.isFullscreen = isFullscreen;
this.resolutionIndex = resolutionIndex;
@ -151,6 +155,7 @@ namespace HeavenStudio.Common
}
// Display / Audio Settings
public bool showSplash;
public bool isFullscreen;
public int resolutionIndex;

View File

@ -1,24 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpriteFlicker : MonoBehaviour
{
public float flickerInterval;
SpriteRenderer sr;
// Start is called before the first frame update
void Start()
{
sr = GetComponent<SpriteRenderer>();
InvokeRepeating("ToggleVisibility", 0f, flickerInterval);
}
// Update is called once per frame
void ToggleVisibility()
{
sr.enabled = !sr.enabled;
}
}

View File

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

View File

@ -223,5 +223,10 @@ namespace HeavenStudio
{
ambientBgGO.SetActive(toggle);
}
public void ToggleCanvasVisibility(bool toggle)
{
canvas.gameObject.SetActive(toggle);
}
}
}

View File

@ -85,11 +85,12 @@ namespace HeavenStudio.Common
return;
}
GameProfiler.instance.perfect = false;
texAnim.Play("GoForAPerfect_Miss");
pAnim.Play("PerfectIcon_Miss", -1, 0);
Jukebox.PlayOneShot("perfectMiss");
if (GameProfiler.instance != null)
GameProfiler.instance.perfect = false;
}
public void Enable(double startBeat)

View File

@ -19,17 +19,24 @@ namespace HeavenStudio.Common
[SerializeField] GameObject TimingDisplayPrefab;
[SerializeField] GameObject SkillStarPrefab;
[SerializeField] GameObject ChartSectionPrefab;
[SerializeField] SectionMedalsManager SectionMedalsManager;
[Header("Components")]
[SerializeField] Transform ComponentHolder;
List<OverlaysManager.OverlayOption> lytElements = new List<OverlaysManager.OverlayOption>();
public static bool OverlaysReady {get { return instance != null &&
TimingAccuracyDisplay.instance != null &&
SkillStarManager.instance != null &&
SectionMedalsManager.instance != null &&
HeavenStudio.Games.Global.Textbox.instance != null;}}
// Start is called before the first frame update
void Start()
public void Start()
{
instance = this;
RefreshOverlaysLayout();
instance = this;
}
// Update is called once per frame
@ -82,12 +89,15 @@ namespace HeavenStudio.Common
{
if (c is TimingDisplayComponent) {
c.CreateElement(TimingDisplayPrefab, ComponentHolder);
Debug.Log("Create TimingDisplayComponent");
}
else if (c is SkillStarComponent) {
c.CreateElement(SkillStarPrefab, ComponentHolder);
Debug.Log("Create SkillStarComponent");
}
else if (c is SectionComponent) {
c.CreateElement(ChartSectionPrefab, ComponentHolder);
Debug.Log("Create SectionComponent");
}
c.PositionElement();
}
@ -225,6 +235,8 @@ namespace HeavenStudio.Common
go.transform.localScale = Vector3.one * scale;
go.transform.localRotation = Quaternion.Euler(0, 0, rotation);
go.SetActive(enable && OverlaysManager.OverlaysEnabled);
HeavenStudio.Common.SectionMedalsManager.instance?.AnchorToOverlay(go);
}
}

View File

@ -20,9 +20,13 @@ namespace HeavenStudio.Common
bool isMedalsEligible = true;
// Start is called before the first frame update
void Start()
public void Awake()
{
instance = this;
}
public void Start()
{
cond = Conductor.instance;
GameManager.instance.onSectionChange += OnSectionChange;
}
@ -33,6 +37,13 @@ namespace HeavenStudio.Common
}
public void AnchorToOverlay(GameObject overlay)
{
transform.position = overlay.transform.position;
transform.rotation = overlay.transform.rotation;
transform.localScale = overlay.transform.localScale;
}
public void MakeIneligible()
{
isMedalsEligible = false;
@ -42,7 +53,7 @@ namespace HeavenStudio.Common
{
isMedalsStarted = false;
isMedalsEligible = true;
foreach (Transform child in MedalsHolder.transform)
foreach (Transform child in MedalsHolder?.transform)
{
Destroy(child.gameObject);
}
@ -59,6 +70,7 @@ namespace HeavenStudio.Common
}
else
{
GameManager.instance.ClearedSection = isMedalsEligible;
GameObject medal = Instantiate(isMedalsEligible ? MedalOkPrefab : MedalMissPrefab, MedalsHolder.transform);
medal.SetActive(true);
isMedalsEligible = true;
@ -70,6 +82,7 @@ namespace HeavenStudio.Common
if (!PersistentDataManager.gameSettings.isMedalOn) return;
if (PersistentDataManager.gameSettings.isMedalOn && isMedalsStarted)
{
GameManager.instance.ClearedSection = isMedalsEligible;
GameObject medal = Instantiate(isMedalsEligible ? MedalOkPrefab : MedalMissPrefab, MedalsHolder.transform);
medal.SetActive(true);
}

View File

@ -22,6 +22,7 @@ namespace HeavenStudio.Common
public float StarTargetTime { get { return starStart + starLength; } }
public bool IsEligible { get; private set; }
public bool IsCollected { get { return state == StarState.Collected; } }
float starStart = float.MaxValue;
float starLength = float.MaxValue;
@ -29,10 +30,10 @@ namespace HeavenStudio.Common
Conductor cond;
// Start is called before the first frame update
void Start()
public void Start()
{
instance = this;
cond = Conductor.instance;
instance = this;
}
// Update is called once per frame

View File

@ -35,7 +35,7 @@ namespace HeavenStudio.Common
float targetArrowPos = 0f;
// Start is called before the first frame update
void Start()
public void Start()
{
instance = this;
}

View File

@ -0,0 +1,192 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using HeavenStudio.Util;
using HeavenStudio.InputSystem;
namespace HeavenStudio.Common
{
public class PauseMenu : MonoBehaviour
{
public enum Options
{
Continue,
StartOver,
Settings,
Quit
}
// TODO
// MAKE OPTIONS ACCEPT MOUSE INPUT
[SerializeField] float patternSpeed = 1f;
[SerializeField] SettingsDialog settingsDialog;
[SerializeField] Animator animator;
[SerializeField] TMP_Text chartTitleText;
[SerializeField] TMP_Text chartArtistText;
[SerializeField] GameObject optionArrow;
[SerializeField] GameObject optionHolder;
[SerializeField] RectTransform patternL;
[SerializeField] RectTransform patternR;
public static bool IsPaused { get { return isPaused; } }
private static bool isPaused = false;
private double pauseBeat;
private bool canPick = false;
private bool isQuitting = false;
private int optionSelected = 0;
void Pause()
{
Conductor.instance.Pause();
pauseBeat = Conductor.instance.songPositionInBeatsAsDouble;
chartTitleText.text = GameManager.instance.Beatmap["remixtitle"];
chartArtistText.text = GameManager.instance.Beatmap["remixauthor"];
animator.Play("PauseShow");
Jukebox.PlayOneShot("ui/PauseIn");
isPaused = true;
canPick = false;
optionSelected = 0;
}
void UnPause(bool instant = false)
{
Conductor.instance.Play(pauseBeat);
if (instant)
{
animator.Play("NoPose");
}
else
{
animator.Play("PauseHide");
Jukebox.PlayOneShot("ui/PauseOut");
}
isPaused = false;
canPick = false;
}
// Start is called before the first frame update
void Start()
{
isPaused = false;
isQuitting = false;
}
// Update is called once per frame
void Update()
{
if (isQuitting) return;
if (PlayerInput.GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadPause))
{
if (isPaused)
{
UnPause();
}
else
{
Pause();
}
}
else if (isPaused && canPick && !settingsDialog.IsOpen)
{
if (Input.GetKeyDown(KeyCode.UpArrow) || PlayerInput.GetInputController(1).GetButtonDown((int)InputController.ButtonsPad.PadUp))
{
optionSelected--;
if (optionSelected < 0)
{
optionSelected = optionHolder.transform.childCount - 1;
}
ChooseOption((Options) optionSelected);
}
else if (Input.GetKeyDown(KeyCode.DownArrow) || PlayerInput.GetInputController(1).GetButtonDown((int)InputController.ButtonsPad.PadDown))
{
optionSelected++;
if (optionSelected > optionHolder.transform.childCount - 1)
{
optionSelected = 0;
}
ChooseOption((Options) optionSelected);
}
else if (Input.GetKeyDown(KeyCode.Return) || PlayerInput.GetInputController(1).GetButtonDown((int)InputController.ButtonsPad.PadE))
{
UseOption((Options) optionSelected);
}
}
if (isPaused)
{
patternL.anchoredPosition = new Vector2((Time.realtimeSinceStartup * patternSpeed) % 13, patternL.anchoredPosition.y);
patternR.anchoredPosition = new Vector2(-(Time.realtimeSinceStartup * patternSpeed) % 13, patternR.anchoredPosition.y);
}
}
public void ChooseCurrentOption()
{
ChooseOption((Options) optionSelected, false);
canPick = true;
}
public void ChooseOption(Options option, bool sound = true)
{
optionArrow.transform.position = new Vector3(optionArrow.transform.position.x, optionHolder.transform.GetChild((int) option).position.y, optionArrow.transform.position.z);
foreach (Transform child in optionHolder.transform)
{
child.transform.localScale = new Vector3(1f, 1f, 1f);
}
optionHolder.transform.GetChild((int) option).transform.localScale = new Vector3(1.2f, 1.2f, 1.2f);
if (sound)
Jukebox.PlayOneShot("ui/UIOption");
}
void UseOption(Options option)
{
switch (option)
{
case Options.Continue:
OnContinue();
break;
case Options.StartOver:
OnRestart();
break;
case Options.Settings:
OnSettings();
Jukebox.PlayOneShot("ui/UISelect");
break;
case Options.Quit:
OnQuit();
break;
}
}
void OnContinue()
{
UnPause();
}
void OnRestart()
{
UnPause(true);
GlobalGameManager.ForceFade(0, 1f, 0.5f);
GameManager.instance.Stop(0, true, 1.5f);
Jukebox.PlayOneShot("ui/UIEnter");
}
void OnQuit()
{
isQuitting = true;
Jukebox.PlayOneShot("ui/PauseQuit");
GlobalGameManager.LoadScene("Editor", 0, 0.1f);
}
void OnSettings()
{
settingsDialog.SwitchSettingsDialog();
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 54588eb7ee0680643aeaf61dcf609903
guid: 013f3797143f4e241a6959ce253780f7
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,39 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio
{
public class Prologue : MonoBehaviour
{
[SerializeField] private float waitSeconds;
public GameObject Holder;
public GameObject pressAny;
bool inPrologue = false;
private void Update()
{
if (Input.anyKeyDown && !inPrologue)
{
pressAny.SetActive(false);
Holder.SetActive(true);
StartCoroutine(Wait());
inPrologue = true;
}
}
IEnumerator Wait()
{
transform.GetChild(0).gameObject.SetActive(false);
yield return new WaitForSeconds(1);
transform.GetChild(0).gameObject.SetActive(true);
yield return new WaitForSeconds(waitSeconds);
transform.GetChild(0).gameObject.SetActive(false);
yield return new WaitForSeconds(2);
UnityEngine.SceneManagement.SceneManager.LoadScene(1);
}
}
}

View File

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

View File

@ -1,145 +0,0 @@
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using DG.Tweening;
using HeavenStudio.Util;
namespace HeavenStudio
{
public class Rating : MonoBehaviour
{
public GameObject Title;
public GameObject Desc;
public GameObject Rank;
public GameObject Epilogue;
public GameObject Perfect;
public GameObject RankingHolder;
public GameObject Fade;
private string rank;
private int rankId;
public Sprite[] epilogueSprites;
public Image epilogueImage;
public TMP_Text epilogueText;
private void Start()
{
float score = GameProfiler.instance.score;
TMP_Text desc = Desc.GetComponent<TMP_Text>();
if (GameProfiler.instance.perfect)
{
Perfect.SetActive(true);
Jukebox.PlayOneShot("Rankings/ranking_perfect");
StartCoroutine(PerfectIE());
}
else
{
if (score < 59)
{
// try again
desc.text = "Your fork technique was rather uncouth. \nYour consecutive stabs needed work.";
rank = "Rankings/ranking_tryagain";
rankId = 2;
}
else if (score >= 59 && score < 79)
{
// ok
desc.text = "Eh. Good enough.";
rank = "Rankings/ranking_ok";
rankId = 1;
}
else if (score >= 79)
{
// superb
desc.text = "Your fork technique was quite elegant. \nYour consecutive stabs were excellent. \nYour triple-stab technique was sublime.";
rank = "Rankings/ranking_superb";
rankId = 0;
}
StartCoroutine(ShowRank());
}
}
private IEnumerator ShowRank()
{
// Title
yield return new WaitForSeconds(0.5f);
Jukebox.PlayOneShot("Rankings/ranking_title_show");
Title.SetActive(true);
// Desc
yield return new WaitForSeconds(2f);
Jukebox.PlayOneShot("Rankings/ranking_desc_show");
Desc.SetActive(true);
// Rating
yield return new WaitForSeconds(2f);
Jukebox.PlayOneShot(rank);
Rank.transform.GetChild(rankId).gameObject.SetActive(true);
// Epilogue
yield return new WaitForSeconds(5f);
Fade.GetComponent<Image>().DOColor(Color.black, 0.75f).OnComplete(delegate
{
StartCoroutine(ShowEpilogue());
});
}
private IEnumerator ShowEpilogue()
{
epilogueImage.sprite = epilogueSprites[rankId];
switch (rankId)
{
case 2:
epilogueText.text = "Blood sugar...so...low...";
break;
case 1:
epilogueText.text = "I could eat two more dinners!";
break;
case 0:
epilogueText.text = "So full! So satisfied!";
break;
}
yield return new WaitForSeconds(1);
Fade.GetComponent<Image>().color = new Color(0, 0, 0, 0);
RankingHolder.SetActive(false);
Epilogue.SetActive(true);
switch (rankId)
{
case 0:
Jukebox.PlayOneShot("Rankings/epilogue_superb");
break;
case 1:
Jukebox.PlayOneShot("Rankings/epilogue_ok");
break;
case 2:
Jukebox.PlayOneShot("Rankings/epilogue_tryagain");
break;
}
yield return new WaitForSeconds(8);
GlobalGameManager.LoadScene(0);
}
private IEnumerator PerfectIE()
{
yield return new WaitForSeconds(8);
GlobalGameManager.LoadScene(0);
}
}
}

View File

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

View File

@ -3,9 +3,9 @@ using UnityEngine;
using UnityEngine.UI;
using TMPro;
using HeavenStudio.Common;
using HeavenStudio.Editor;
namespace HeavenStudio.Editor
namespace HeavenStudio.Common
{
public class SettingsDialog : Dialog
{
@ -18,21 +18,25 @@ namespace HeavenStudio.Editor
public void SwitchSettingsDialog()
{
if(dialog.activeSelf) {
Editor.instance.canSelect = true;
Editor.instance.inAuthorativeMenu = false;
dialog.SetActive(false);
PersistentDataManager.SaveSettings();
tabsManager.CleanTabs();
if (Editor.Editor.instance == null) return;
Editor.Editor.instance.canSelect = true;
Editor.Editor.instance.inAuthorativeMenu = false;
} else {
ResetAllDialogs();
Editor.instance.canSelect = false;
Editor.instance.inAuthorativeMenu = true;
dialog.SetActive(true);
tabsManager.GenerateTabs(tabs);
BuildDateDisplay.text = GlobalGameManager.buildTime;
if (Editor.Editor.instance == null) return;
Editor.Editor.instance.canSelect = false;
Editor.Editor.instance.inAuthorativeMenu = true;
}
}

View File

@ -11,8 +11,8 @@ namespace HeavenStudio.Editor
{
public class CreditsLegalSettings : TabsContent
{
private int SecretCounter = 0;
private bool SecretActive = false;
private static int SecretCounter = 0;
private static bool SecretActive = false;
[SerializeField] private TextAsset creditsText;
[SerializeField] private TMP_Text creditsDisplay;
[SerializeField] private GameObject secretObject;
@ -41,7 +41,14 @@ namespace HeavenStudio.Editor
Jukebox.PlayOneShot("applause");
Debug.Log("Activating Studio Dance...");
Editor.instance.StudioDanceManager.OpenDanceWindow();
if (Editor.instance == null)
{
}
else
{
Editor.instance.StudioDanceManager.OpenDanceWindow();
}
}
public void MakeSecretInactive()
@ -49,7 +56,15 @@ namespace HeavenStudio.Editor
SecretCounter = 0;
secretObject.SetActive(false);
SecretActive = false;
Editor.instance.StudioDanceManager.CloseDanceWindow();
if (Editor.instance == null)
{
}
else
{
Editor.instance.StudioDanceManager.CloseDanceWindow();
}
}
public override void OnOpenTab()

View File

@ -10,6 +10,7 @@ namespace HeavenStudio.Editor
{
public class DispAudioSettings : TabsContent
{
[SerializeField] Toggle splashScreenToggle;
public TMP_Dropdown resolutionsDropdown;
public GameObject customSetter;
public TMP_InputField widthInputField, heightInputField;
@ -96,8 +97,14 @@ namespace HeavenStudio.Editor
PersistentDataManager.gameSettings.masterVolume = volSlider.value;
}
public void OnSplashChanged()
{
PersistentDataManager.gameSettings.showSplash = splashScreenToggle.isOn;
}
public override void OnOpenTab()
{
splashScreenToggle.isOn = PersistentDataManager.gameSettings.showSplash;
resolutionsDropdown.value = GlobalGameManager.ScreenSizeIndex;
widthInputField.text = GlobalGameManager.CustomScreenWidth.ToString();

View File

@ -1,4 +1,4 @@
namespace HeavenStudio
namespace HeavenStudio.Util
{
public class GameEvent
{

View File

@ -56,6 +56,28 @@ namespace HeavenStudio.Util
}
}
/// <summary>
/// Pauses all currently playing sounds.
/// </summary>
public static void PauseOneShots()
{
if (oneShotAudioSource != null)
{
oneShotAudioSource.Pause();
}
}
/// <summary>
/// Unpauses all currently playing sounds.
/// </summary>
public static void UnpauseOneShots()
{
if (oneShotAudioSource != null)
{
oneShotAudioSource.UnPause();
}
}
/// <summary>
/// Gets the length of an audio clip
/// </summary>

View File

@ -43,7 +43,7 @@ namespace HeavenStudio.Util
if (beat == -1 && !scheduled)
{
audioSource.PlayScheduled(AudioSettings.dspTime);
audioSource.Play();
playInstant = true;
played = true;
startTime = cnd.songPositionAsDouble;
@ -65,7 +65,7 @@ namespace HeavenStudio.Util
{
if (scheduled)
{
if (AudioSettings.dspTime > scheduledTime)
if (scheduledPitch != 0 && AudioSettings.dspTime > scheduledTime)
{
StartCoroutine(NotRelyOnBeatSound());
played = true;
@ -73,7 +73,7 @@ namespace HeavenStudio.Util
}
else if (!playInstant)
{
if (AudioSettings.dspTime > startTime)
if (scheduledPitch != 0 && AudioSettings.dspTime > startTime)
{
played = true;
StartCoroutine(NotRelyOnBeatSound());
@ -82,9 +82,21 @@ namespace HeavenStudio.Util
{
if (!played && scheduledPitch != cnd.SongPitch)
{
scheduledPitch = cnd.SongPitch;
startTime = (AudioSettings.dspTime + (cnd.GetSongPosFromBeat(beat) - cnd.songPositionAsDouble)/(double)scheduledPitch);
audioSource.SetScheduledStartTime(startTime);
if (cnd.SongPitch == 0)
{
scheduledPitch = cnd.SongPitch;
audioSource.Pause();
}
else
{
if (scheduledPitch == 0)
{
audioSource.UnPause();
}
scheduledPitch = cnd.SongPitch;
startTime = (AudioSettings.dspTime + (cnd.GetSongPosFromBeat(beat) - cnd.songPositionAsDouble)/(double)scheduledPitch);
audioSource.SetScheduledStartTime(startTime);
}
}
}
}