mirror of
https://github.com/RHeavenStudio/HeavenStudio.git
synced 2025-06-12 12:37:37 +02:00
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:
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user