void UpdateProDrums(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, uint noteStreak, LaneInfo laneInfo) { DrumsNoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote; int tomsInputMask = DrumsInput.GetProDrumsTomPressedInputMask(laneInfo); int cymbalsInputMask = DrumsInput.GetProDrumsCymbalPressedInputMask(laneInfo); if (nextNoteToHit != null) { // process toms bool tomsHitSuccess = false; { int tomsNoteMask = nextNoteToHit.note.GetMaskWithRequiredFlags(Note.Flags.None); DrumsNoteHitKnowledge.InputTiming tomsHitTimingTracker = nextNoteToHit.standardPadTiming; tomsHitSuccess = ShouldHitAndProcessMiss(laneInfo, time, tomsInputMask, tomsNoteMask, tomsHitTimingTracker); } // process cymbals bool cymbalsHitSuccess = false; { int cymbalsNoteMask = nextNoteToHit.note.GetMaskWithRequiredFlags(Note.Flags.ProDrums_Cymbal); DrumsNoteHitKnowledge.InputTiming cymbalsHitTimingTracker = nextNoteToHit.cymbalPadTiming; cymbalsHitSuccess = ShouldHitAndProcessMiss(laneInfo, time, cymbalsInputMask, cymbalsNoteMask, cymbalsHitTimingTracker); } if (tomsHitSuccess && cymbalsHitSuccess) { HitNote(time, nextNoteToHit); } } else if (tomsInputMask != 0 || cymbalsInputMask != 0) { Debug.Log("Missed due to hitting pad when there was no hit in window"); MissNote(time, MissSubType.Overhit); } }
protected int UpdateWindowExit <TNoteHitKnowledge>(float time, HitWindow <TNoteHitKnowledge> hitWindow) where TNoteHitKnowledge : NoteHitKnowledge { uint noteStreak = stats.noteStreak; int missCount = 0; { var notesRemoved = hitWindow.DetectExit(time); foreach (var noteKnowledge in notesRemoved) { // Miss, exited window if (!noteKnowledge.hasBeenHit) { foreach (Note chordNote in noteKnowledge.note.chord) { chordNote.controller.sustainBroken = true; if (noteStreak > 0) { chordNote.controller.DeactivateNote(); } } ++missCount; } } } return(missCount); }
void UpdateNoteKnowledge(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow, int inputMask, bool strummed, uint noteStreak, GuitarNoteHitKnowledge nextNoteToHit, GuitarSustainHitKnowledge sustainKnowledge) { // Check if it's valid to query the last hit note if (noteStreak <= 0 || lastNoteHit == null || !hitWindow.IsWithinTimeWindow(lastNoteHit.note, nextNoteToHit != null ? nextNoteToHit.note : null, time)) { lastNoteHit = null; } if (nextNoteToHit != null && noteStreak > 0) // None of this knowledge should be used for recovery { if (nextNoteToHit.strumCounter > 1) { nextNoteToHit.strumCounter = 1; // Make this still valid to hit because it's still in the hit window for a reason } // Fill out note knowledge if (GameplayInputFunctions.ValidateFrets(nextNoteToHit.note, inputMask, noteStreak, sustainKnowledge.extendedSustainsMask)) { nextNoteToHit.fretValidationTime = time; } else { nextNoteToHit.lastestFretInvalidationTime = time; } if (GameplayInputFunctions.ValidateStrum(nextNoteToHit.note, canTap, strummed, noteStreak)) { nextNoteToHit.strumValidationTime = time; } else { nextNoteToHit.lastestStrumInvalidationTime = time; } if (strummed) { if (lastNoteHit != null && lastNoteHit.strumCounter <= 0)// lastNoteHit.note.type != Note.Note_Type.Strum) { ++lastNoteHit.strumCounter; } else { ++nextNoteToHit.strumCounter; } } } }
public void Update(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, uint noteStreak, LaneInfo laneInfo) { switch (GameSettings.drumsModeOptions) { case GameSettings.DrumModeOptions.ProDrums: { UpdateProDrums(time, hitWindow, noteStreak, laneInfo); break; } default: { UpdateStandardDrums(time, hitWindow, noteStreak, laneInfo); break; } } }
public void Update(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, GamepadInput drumsInput) { uint noteStreak = stats.noteStreak; int missCount = UpdateWindowExit(time, hitWindow); LaneInfo laneInfo = ChartEditor.Instance.laneInfo; for (int i = 0; i < missCount; ++i) { if (noteStreak > 0) { Debug.Log("Missed due to note falling out of window"); } MissNote(time, DrumsNoteHitAndMissDetect.MissSubType.NoteMiss, null); } hitAndMissNoteDetect.Update(time, hitWindow, drumsInput, stats.noteStreak, laneInfo); }
// Update is called once per frame public void Update(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow) { int missCount = UpdateWindowExit(time, hitWindow); for (int i = 0; i < missCount; ++i) { if (stats.noteStreak > 0) { Debug.Log("Missed due to note falling out of window"); } MissNote(time, GuitarNoteHitAndMissDetect.MissSubType.NoteMiss, null); } guitarSustainHitKnowledge.Update(time); sustainBreakDetect.Update(time, guitarSustainHitKnowledge, stats.noteStreak); hitAndMissNoteDetect.Update(time, hitWindow, stats.noteStreak, guitarSustainHitKnowledge); }
void PreserveStreakDetect(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow, bool strummed, uint noteStreak, GuitarNoteHitKnowledge nextNoteToHit, int inputMask) { if (nextNoteToHit.strumCounter > 1) { MissNote(time, MissSubType.Overstrum); Debug.Log("Missed note due to double strumming on a single note"); } else if (nextNoteToHit.fretsValidated && nextNoteToHit.strumValidated && Mathf.Abs(nextNoteToHit.fretValidationTime - nextNoteToHit.strumValidationTime) <= GuitarTiming.slopBufferTime) { HitNote(time, nextNoteToHit); } else if (nextNoteToHit.strumValidated && Mathf.Abs(time - nextNoteToHit.strumValidationTime) > GuitarTiming.slopBufferTime && nextNoteToHit.strumCounter > 0) { MissNote(time, MissSubType.Overstrum); Debug.Log("Missed note due to strum expiration"); nextNoteToHit.strumValidationTime = GuitarNoteHitKnowledge.NULL_TIME; } }
public void Update(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow, uint noteStreak, GuitarSustainHitKnowledge sustainKnowledge) { // Capture input bool strum = GuitarInput.GetStrumInput(); int inputMask = GuitarInput.GetFretInputMask(); if (inputMask != previousInputMask) { canTap = true; } if (strum) { WriteInputToChart(time, inputMask); } // What note is the player trying to hit next? GuitarNoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote; UpdateNoteKnowledge(time, hitWindow, inputMask, strum, noteStreak, nextNoteToHit, sustainKnowledge); if (nextNoteToHit != null) { Note nextSeperate = nextNoteToHit.note.nextSeperateNote; if (noteStreak > 0) { PreserveStreakDetect(time, hitWindow, strum, noteStreak, nextNoteToHit, inputMask); } else { RecoveryDetect(time, hitWindow, inputMask, strum, noteStreak); } } // No note in window else { BlankWindowDetect(time, strum); } previousInputMask = inputMask; }
public void Update(float time, HitWindow <NoteHitKnowledge> hitWindow) { NoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote; if (nextNoteToHit != null) { NoteController nCon = nextNoteToHit.note.controller; if (nCon != null) { Vector3 notePosition = nCon.transform.position; Vector3 strikelinePosition = ChartEditor.Instance.visibleStrikeline.position; bool belowStrikeLine = notePosition.y <= strikelinePosition.y + (Time.deltaTime * GameSettings.hyperspeed / GameSettings.gameSpeed); if (belowStrikeLine) { HitNote(time, nextNoteToHit); } } } }
public void Update(float time, HitWindow <NoteHitKnowledge> hitWindow) { NoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote; while (nextNoteToHit != null) // The bot is allowed to hit more than 1 note per frame { NoteController nCon = nextNoteToHit.note.controller; if (nCon != null) { Vector3 notePosition = nCon.transform.position; Vector3 strikelinePosition = ChartEditor.Instance.visibleStrikeline.position; float visualOffset = Time.deltaTime / Globals.gameSettings.hyperspeed * Globals.gameSettings.gameSpeed; // We want to hit it just before it crosses the strikeline. Looks a bit better. bool belowStrikeLine = notePosition.y <= strikelinePosition.y + visualOffset; if (belowStrikeLine) { HitNote(time, nextNoteToHit); nextNoteToHit = hitWindow.oldestUnhitNote; } else { nextNoteToHit = null; } } } // Note that having this logic here essentially gives the bot an infinite backend window in case of a framerate hiccup. int missCount = UpdateWindowExit(time, hitWindow); for (int i = 0; i < missCount; ++i) { if (stats.noteStreak > 0) { Debug.Log("Bot missed due to note falling out of window. There may be more notes in the window thatn the framerate can handle"); } MissNote(time, GuitarNoteHitAndMissDetect.MissSubType.NoteMiss, null); } }
void UpdateStandardDrums(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, uint noteStreak, LaneInfo laneInfo) { DrumsNoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote; int inputMask = DrumsInput.GetPadPressedInputMask(laneInfo); if (nextNoteToHit != null) { int noteMask = nextNoteToHit.note.mask; DrumsNoteHitKnowledge.InputTiming hitTimingTracker = nextNoteToHit.standardPadTiming; bool standardPadSuccess = ShouldHitAndProcessMiss(laneInfo, time, inputMask, noteMask, hitTimingTracker); if (standardPadSuccess) { HitNote(time, nextNoteToHit); } } else if (inputMask != 0) { Debug.Log("Missed due to hitting pad when there was no hit in window"); MissNote(time, MissSubType.Overhit); } }
void RecoveryDetect(float time, HitWindow <GuitarNoteHitKnowledge> hitWindow, int fretInputMask, bool strummed, uint noteStreak) { var noteKnowledgeList = hitWindow.noteKnowledgeQueue; // Search to see if user is hitting a note ahead List <GuitarNoteHitKnowledge> validatedNotes = new List <GuitarNoteHitKnowledge>(); foreach (GuitarNoteHitKnowledge noteKnowledge in noteKnowledgeList) { // Collect all notes the user is possibly hitting if ( GameplayInputFunctions.ValidateFrets(noteKnowledge.note, fretInputMask, noteStreak) && GameplayInputFunctions.ValidateStrum(noteKnowledge.note, canTap, strummed, noteStreak) ) { validatedNotes.Add(noteKnowledge); } } if (validatedNotes.Count > 0) { // Recovery algorithm // Select the note closest to the strikeline float aimYPos = ChartEditor.Instance.visibleStrikeline.transform.position.y + 0.25f; // Added offset from the note controller GuitarNoteHitKnowledge selectedNote = validatedNotes[0]; float dis = -1; foreach (GuitarNoteHitKnowledge validatedNote in validatedNotes) { if (!selectedNote.note.controller) { return; } NoteController noteController = selectedNote.note.controller; float distance = Mathf.Abs(aimYPos - noteController.transform.position.y); if (distance < dis || dis < 0) { selectedNote = validatedNote; dis = distance; } } int index = noteKnowledgeList.IndexOf(selectedNote); GuitarNoteHitKnowledge note = noteKnowledgeList[index]; // Recovery missed notes if (index > 0) { Debug.Log("Missed notes when performing recovery. Notes skipped = " + index); } for (int missedCounter = 0; missedCounter < index; ++missedCounter) { MissNote(time, MissSubType.NoteMiss, noteKnowledgeList[missedCounter]); } HitNote(time, note); // We fill out our own knowledge note.fretValidationTime = time; note.strumValidationTime = time; if (strummed) { ++note.strumCounter; } } else if (strummed) { MissNote(time, MissSubType.Overstrum); Debug.Log("Missed due to strumming when there were no notes to strum during recovery"); } }
public void Update(float time, HitWindow <DrumsNoteHitKnowledge> hitWindow, uint noteStreak, LaneInfo laneInfo) { DrumsNoteHitKnowledge nextNoteToHit = hitWindow.oldestUnhitNote; int inputMask = DrumsInput.GetPadPressedInputMask(laneInfo); if (nextNoteToHit != null) { int noteMask = nextNoteToHit.note.mask; int laneMask = laneInfo.laneMask; // Cull notes from the notemask by lanes that are being used foreach (Note.DrumPad pad in EnumX <Note.DrumPad> .Values) { if (pad == Note.DrumPad.Kick) { continue; } int padBitInput = (int)pad; int padMask = 1 << padBitInput; bool includeLane = (padMask & laneMask) != 0; if (!includeLane) { noteMask &= ~padMask; } } bool badHit = false; if ((inputMask | noteMask) != noteMask) { badHit = true; } else { foreach (Note.DrumPad drumPad in EnumX <Note.DrumPad> .Values) { bool hitPad = DrumsInput.GetPadPressedInput(drumPad, laneInfo); if (hitPad) { if (nextNoteToHit.GetHitTime(drumPad) == NoteHitKnowledge.NULL_TIME) { nextNoteToHit.SetHitTime(drumPad, time); } else { badHit = true; } } } } if (badHit) { // Bad input Debug.Log("Missed due to bad input"); MissNote(time, MissSubType.Overhit); foreach (Note.DrumPad drumPad in EnumX <Note.DrumPad> .Values) { nextNoteToHit.SetHitTime(drumPad, NoteHitKnowledge.NULL_TIME); } } else { float min = float.MaxValue, max = float.MinValue; int totalHitsMask = 0; foreach (Note.DrumPad drumPad in EnumX <Note.DrumPad> .Values) { if (nextNoteToHit.GetHitTime(drumPad) != NoteHitKnowledge.NULL_TIME) { float hitTime = nextNoteToHit.GetHitTime(drumPad); min = Mathf.Min(min, hitTime); max = Mathf.Max(max, hitTime); totalHitsMask |= 1 << (int)drumPad; } } float totalSlop = max - min; if (min != float.MaxValue && time - min > DrumsTiming.slopBufferTime) { // Technically an underhit Debug.Log("Missed due to underhit"); MissNote(time, MissSubType.Overhit); } else if (totalHitsMask == noteMask && totalSlop < DrumsTiming.slopBufferTime) { HitNote(time, nextNoteToHit); } } } else if (inputMask != 0) { Debug.Log("Missed due to hitting pad when there was no hit in window"); MissNote(time, MissSubType.Overhit); } }