port PlayerActionEvent IsHittable

rename timing margin values
simplify some player action event logic
This commit is contained in:
minenice55 2023-06-25 18:53:36 -04:00
parent 6585753545
commit b9c5fd4581
7 changed files with 61 additions and 58 deletions

View file

@ -233,7 +233,7 @@ namespace HeavenStudio.Games.Scripts_CropStomp
stompedBeat = cond.songPositionInBeatsAsDouble;
landBeat = targetBeat + (float)cond.SecsToBeats(Minigame.EndTime()-1, cond.GetBpmAtBeat(targetBeat));
landBeat = targetBeat + (float)cond.SecsToBeats(Minigame.NgLateTime()-1, cond.GetBpmAtBeat(targetBeat));
if (autoTriggered)
{

View file

@ -201,7 +201,7 @@ namespace HeavenStudio.Games.Scripts_KarateMan
switch (forceHand)
{
case 0:
if (cond.songPositionInBeatsAsDouble - lastPunchTime < 0.25f + (Minigame.LateTime() - 1f))
if (cond.songPositionInBeatsAsDouble - lastPunchTime < 0.25f + (Minigame.JustLateTime() - 1f))
{
lastPunchTime = double.MinValue;
anim.DoScaledAnimationAsync("Straight", 0.5f);

View file

@ -9,7 +9,7 @@ namespace HeavenStudio.Games
{
public class Minigame : MonoBehaviour
{
public static double earlyTime = 0.075f, perfectTime = 0.06f, aceEarlyTime = 0.01f, aceLateTime = 0.01f, lateTime = 0.06f, endTime = 0.075f;
public static double ngEarlyTime = 0.075f, justEarlyTime = 0.06f, aceEarlyTime = 0.01f, aceLateTime = 0.01f, justLateTime = 0.06f, ngLateTime = 0.075f;
public static float rankHiThreshold = 0.8f, rankOkThreshold = 0.6f;
[SerializeField] public SoundSequence.SequenceKeyValue[] SoundSequences;
@ -45,7 +45,9 @@ namespace HeavenStudio.Games
InputType inputType,
PlayerActionEvent.ActionEventCallbackState OnHit,
PlayerActionEvent.ActionEventCallback OnMiss,
PlayerActionEvent.ActionEventCallback OnBlank)
PlayerActionEvent.ActionEventCallback OnBlank,
PlayerActionEvent.ActionEventHittableQuery HittableQuery = null
)
{
GameObject evtObj = new GameObject("ActionEvent" + (startBeat+timer));
@ -59,6 +61,7 @@ namespace HeavenStudio.Games
evt.OnHit = OnHit;
evt.OnMiss = OnMiss;
evt.OnBlank = OnBlank;
evt.IsHittable = HittableQuery;
evt.OnDestroy = RemoveScheduledInput;
@ -98,8 +101,6 @@ namespace HeavenStudio.Games
return evt;
}
//Clean up method used whenever a PlayerActionEvent has finished
public void RemoveScheduledInput(PlayerActionEvent evt)
{
@ -151,49 +152,36 @@ namespace HeavenStudio.Games
}
// now should fix the fast bpm problem
public static double EarlyTime()
public static double NgEarlyTime()
{
return 1f - earlyTime;
return 1f - ngEarlyTime;
}
public static double PerfectTime()
public static double JustEarlyTime()
{
return 1f - perfectTime;
return 1f - justEarlyTime;
}
public static double LateTime()
public static double JustLateTime()
{
return 1f + lateTime;
return 1f + justLateTime;
}
public static double EndTime()
public static double NgLateTime()
{
return 1f + endTime;
return 1f + ngLateTime;
}
public static double AceStartTime()
public static double AceEarlyTime()
{
return 1f - aceEarlyTime;
}
public static double AceEndTime()
public static double AceLateTime()
{
return 1f + aceLateTime;
}
// 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;
float a = bpm / 120f;
float b = (Mathf.Log(a) + 2f) * 0.5f;
float r = Mathf.Lerp(a, b, 0.25f);
return r * f;
}
public int firstEnable = 0;
public virtual void OnGameSwitch(double beat)
{
//Below is a template that can be used for handling previous entities.
@ -263,7 +251,7 @@ namespace HeavenStudio.Games
public void ScoreMiss(double weight = 1f)
{
GameManager.instance.ScoreInputAccuracy(0, true, EndTime(), weight, false);
GameManager.instance.ScoreInputAccuracy(0, true, NgLateTime(), weight, false);
if (weight > 0)
{
GoForAPerfect.instance.Miss();

View file

@ -18,10 +18,12 @@ namespace HeavenStudio.Games
public static bool EnableAutoplayCheat = true;
public delegate void ActionEventCallback(PlayerActionEvent caller);
public delegate void ActionEventCallbackState(PlayerActionEvent caller, float state);
public delegate bool ActionEventHittableQuery();
public ActionEventCallbackState OnHit; //Function to trigger when an input has been done perfectly
public ActionEventCallback OnMiss; //Function to trigger when an input has been missed
public ActionEventCallback OnBlank; //Function to trigger when an input has been recorded while this is pending
public ActionEventHittableQuery IsHittable; //Checks if an input can be hit. Returning false will skip button checks.
public ActionEventCallback OnDestroy; //Function to trigger whenever this event gets destroyed. /!\ Shouldn't be used for a minigame! Use OnMiss instead /!\
@ -55,6 +57,11 @@ namespace HeavenStudio.Games
this.OnMiss = OnMiss;
}
public void setHittableQuery(ActionEventHittableQuery IsHittable)
{
this.IsHittable = IsHittable;
}
public void Enable() { enabled = true; }
public void Disable() { enabled = false; }
public void QueueDeletion() { markForDeletion = true; }
@ -105,7 +112,7 @@ namespace HeavenStudio.Games
}
//BUGFIX: ActionEvents destroyed too early
if (normalizedTime > Minigame.EndTime()) Miss();
if (normalizedTime > Minigame.NgLateTime()) Miss();
if (lockedByEvent)
{
@ -116,11 +123,11 @@ namespace HeavenStudio.Games
return;
}
if (!autoplayOnly && IsCorrectInput())
if (!autoplayOnly && (IsHittable == null || IsHittable != null && IsHittable()) && IsCorrectInput())
{
if (IsExpectingInputNow())
{
double stateProg = ((normalizedTime - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2;
double stateProg = ((normalizedTime - Minigame.JustEarlyTime()) / (Minigame.JustLateTime() - Minigame.JustEarlyTime()) - 0.5f) * 2;
Hit(stateProg, normalizedTime);
}
else
@ -186,8 +193,16 @@ namespace HeavenStudio.Games
public bool IsExpectingInputNow()
{
if (IsHittable != null)
{
if (!IsHittable()) return false;
}
if (!enabled) return false;
if (!isEligible) return false;
if (markForDeletion) return false;
double normalizedBeat = GetNormalizedTime();
return normalizedBeat > Minigame.EarlyTime() && normalizedBeat < Minigame.EndTime();
return normalizedBeat > Minigame.NgEarlyTime() && normalizedBeat < Minigame.NgLateTime();
}
double GetNormalizedTime()
@ -195,9 +210,9 @@ namespace HeavenStudio.Games
var cond = Conductor.instance;
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;
// HS timing window uses 1 as the middle point instead of 0
return 1 + (currTime - targetTime);
}
//For the Autoplay
@ -210,7 +225,7 @@ namespace HeavenStudio.Games
else
{
double normalizedBeat = GetNormalizedTime();
double stateProg = ((normalizedBeat - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2;
double stateProg = ((normalizedBeat - Minigame.JustEarlyTime()) / (Minigame.JustLateTime() - Minigame.JustEarlyTime()) - 0.5f) * 2;
Hit(stateProg, normalizedBeat);
}
}
@ -251,27 +266,27 @@ namespace HeavenStudio.Games
double TimeToAccuracy(double time)
{
if (time >= Minigame.AceStartTime() && time <= Minigame.AceEndTime())
if (time >= Minigame.AceEarlyTime() && time <= Minigame.AceLateTime())
{
// Ace
return 1.0;
}
double state = 0;
if (time >= Minigame.PerfectTime() && time <= Minigame.LateTime())
if (time >= Minigame.JustEarlyTime() && time <= Minigame.JustLateTime())
{
// Good Hit
if (time > 1.0)
{
// late half of timing window
state = 1.0 - ((time - Minigame.AceEndTime()) / (Minigame.LateTime() - Minigame.AceEndTime()));
state = 1.0 - ((time - Minigame.AceLateTime()) / (Minigame.JustLateTime() - Minigame.AceLateTime()));
state *= 1.0 - Minigame.rankHiThreshold;
state += Minigame.rankHiThreshold;
}
else
{
//early half of timing window
state = ((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime()));
state = ((time - Minigame.JustEarlyTime()) / (Minigame.AceEarlyTime() - Minigame.JustEarlyTime()));
state *= 1.0 - Minigame.rankHiThreshold;
state += Minigame.rankHiThreshold;
}
@ -281,13 +296,13 @@ namespace HeavenStudio.Games
if (time > 1.0)
{
// late half of timing window
state = 1.0 - ((time - Minigame.LateTime()) / (Minigame.EndTime() - Minigame.LateTime()));
state = 1.0 - ((time - Minigame.JustLateTime()) / (Minigame.NgLateTime() - Minigame.JustLateTime()));
state *= Minigame.rankOkThreshold;
}
else
{
//early half of timing window
state = ((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime()));
state = ((time - Minigame.JustEarlyTime()) / (Minigame.AceEarlyTime() - Minigame.JustEarlyTime()));
state *= Minigame.rankOkThreshold;
}
}

View file

@ -343,7 +343,7 @@ namespace HeavenStudio.Games.Scripts_SpaceSoccer
var cond = Conductor.instance;
ball = null;
// queue the miss sound
MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound("spaceSoccer/missNeutral", targetBeat + (float)cond.SecsToBeats(Minigame.EndTime()-1,
MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound("spaceSoccer/missNeutral", targetBeat + (float)cond.SecsToBeats(Minigame.NgLateTime()-1,
cond.GetBpmAtBeat(targetBeat)), SoundByte.GetPitchFromCents(UnityEngine.Random.Range(-75, 75), false)) });
}

View file

@ -41,13 +41,13 @@ namespace HeavenStudio.Common
{
if (cond.songPositionInBeatsAsDouble > starStart && state == StarState.In)
{
double offset = cond.SecsToBeats(Minigame.AceStartTime()-1, cond.GetBpmAtBeat(StarTargetTime));
double offset = cond.SecsToBeats(Minigame.AceEarlyTime()-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));
offset = cond.SecsToBeats(Minigame.AceLateTime()-1, cond.GetBpmAtBeat(StarTargetTime));
if (cond.songPositionInBeatsAsDouble > starStart + starLength + offset)
KillStar();
}
@ -94,8 +94,8 @@ namespace HeavenStudio.Common
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))
cond.songPositionInBeatsAsDouble >= StarTargetTime + cond.SecsToBeats(Minigame.AceEarlyTime()-1, cond.GetBpmAtBeat(StarTargetTime)) &&
cond.songPositionInBeatsAsDouble <= StarTargetTime + cond.SecsToBeats(Minigame.AceLateTime()-1, cond.GetBpmAtBeat(StarTargetTime))
)
{
state = StarState.Collected;

View file

@ -87,12 +87,12 @@ namespace HeavenStudio.Common
// SetArrowPos(time);
// no Clamp() because double
time = System.Math.Max(Minigame.EarlyTime(), System.Math.Min(Minigame.EndTime(), time));
time = System.Math.Max(Minigame.NgEarlyTime(), System.Math.Min(Minigame.NgLateTime(), time));
if (time >= Minigame.AceStartTime() && time <= Minigame.AceEndTime())
if (time >= Minigame.AceEarlyTime() && time <= Minigame.AceLateTime())
{
type = Rating.Just;
frac = (float)((time - Minigame.AceStartTime()) / (Minigame.AceEndTime() - Minigame.AceStartTime()));
frac = (float)((time - Minigame.AceEarlyTime()) / (Minigame.AceLateTime() - Minigame.AceEarlyTime()));
y = barJustTransform.localScale.y * frac - (barJustTransform.localScale.y * 0.5f);
}
else
@ -100,32 +100,32 @@ namespace HeavenStudio.Common
if (time > 1.0)
{
// goes "down"
if (time <= Minigame.LateTime())
if (time <= Minigame.JustLateTime())
{
type = Rating.OK;
frac = (float)((time - Minigame.AceEndTime()) / (Minigame.LateTime() - Minigame.AceEndTime()));
frac = (float)((time - Minigame.AceLateTime()) / (Minigame.JustLateTime() - Minigame.AceLateTime()));
y = ((barOKTransform.localScale.y - barJustTransform.localScale.y) * frac) + barJustTransform.localScale.y;
}
else
{
type = Rating.NG;
frac = (float)((time - Minigame.LateTime()) / (Minigame.EndTime() - Minigame.LateTime()));
frac = (float)((time - Minigame.JustLateTime()) / (Minigame.NgLateTime() - Minigame.JustLateTime()));
y = ((barNGTransform.localScale.y - barOKTransform.localScale.y) * frac) + barOKTransform.localScale.y;
}
}
else
{
// goes "up"
if (time >= Minigame.PerfectTime())
if (time >= Minigame.JustEarlyTime())
{
type = Rating.OK;
frac = (float)((time - Minigame.PerfectTime()) / (Minigame.AceStartTime() - Minigame.PerfectTime()));
frac = (float)((time - Minigame.JustEarlyTime()) / (Minigame.AceEarlyTime() - Minigame.JustEarlyTime()));
y = ((barOKTransform.localScale.y - barJustTransform.localScale.y) * -frac) - barJustTransform.localScale.y;
}
else
{
type = Rating.NG;
frac = (float)((time - Minigame.EarlyTime()) / (Minigame.PerfectTime() - Minigame.EarlyTime()));
frac = (float)((time - Minigame.NgEarlyTime()) / (Minigame.JustEarlyTime() - Minigame.NgEarlyTime()));
y = ((barNGTransform.localScale.y - barOKTransform.localScale.y) * -frac) - barOKTransform.localScale.y;
}
}