Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions RhythmGameUtilities/Enums/JudgmentType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace RhythmGameUtilities
{

public enum JudgmentType
{

PERFECT,

NICE,

GOOD,

OK,

MISS

}

}
118 changes: 118 additions & 0 deletions RhythmGameUtilities/Scripts/SongManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace RhythmGameUtilities
{

public class SongManager
{

public Stats stats { get; protected set; }

public Song song { get; protected set; }

protected readonly List<Note> _remainingNotes = new();

protected int _tick;

public SongManager(Song song, Difficulty difficulty, float comboStep = Stats.DefaultComboStep)
{
this.song = song;

stats = new Stats { difficulty = difficulty, comboStep = comboStep };

_remainingNotes = GetAllNotes(difficulty).Where(note => note.HandPosition < 5).ToList();
}

public Note[] GetAllNotes(Difficulty difficulty)
{
if (song.Difficulties?[difficulty] == null)

Check failure on line 30 in RhythmGameUtilities/Scripts/SongManager.cs

View workflow job for this annotation

GitHub Actions / test-csharp

'Song' does not contain a definition for 'Difficulties' and no accessible extension method 'Difficulties' accepting a first argument of type 'Song' could be found (are you missing a using directive or an assembly reference?)
{
throw new InvalidOperationException($"{difficulty} difficulty not found in song!");
}

if (!song.Difficulties.TryGetValue(difficulty, out var notes))

Check failure on line 35 in RhythmGameUtilities/Scripts/SongManager.cs

View workflow job for this annotation

GitHub Actions / test-csharp

'Song' does not contain a definition for 'Difficulties' and no accessible extension method 'Difficulties' accepting a first argument of type 'Song' could be found (are you missing a using directive or an assembly reference?)
{
throw new InvalidOperationException($"No notes found for the {difficulty} difficulty!");
}

return notes;
}

public List<Note> GetRemainingNotes()
{
return _remainingNotes.ToList();
}

public List<Note> GetActiveNotes(float tickBuffer)
{
var activeNotes = GetRemainingNotes().Where(note =>
_tick > note.Position - tickBuffer / 2 && _tick < note.Position + tickBuffer / 2).ToList();

return activeNotes;
}

protected void ClearMissedNotes()
{
var notesToClear = GetRemainingNotes().Where(note => note.Position + song.BaseBPM / 2 < _tick);

Check failure on line 58 in RhythmGameUtilities/Scripts/SongManager.cs

View workflow job for this annotation

GitHub Actions / test-csharp

'Song' does not contain a definition for 'BaseBPM' and no accessible extension method 'BaseBPM' accepting a first argument of type 'Song' could be found (are you missing a using directive or an assembly reference?)

foreach (var note in notesToClear)
{
ClearMissedNote(note);
}
}

protected virtual void ClearMissedNote(Note note)
{
stats.AddJudgment(JudgmentType.MISS);
stats.ClearCombo();
}

protected virtual void HitNoteHandler(Note note, float accuracy, JudgmentType judgmentType)
{
Console.WriteLine($"Hit note with {accuracy} accuracy and a hit note type of {judgmentType}!");
}

protected virtual void MissNoteHandler(Note note)
{
Console.WriteLine("Missed note!");
}

protected virtual JudgmentType CalculateJudgmentTypeFromAccuracy(float accuracy)
{
return accuracy switch
{
> 0.8f => JudgmentType.PERFECT,
> 0.6f => JudgmentType.NICE,
> 0.3f => JudgmentType.GOOD,
> 0 => JudgmentType.OK,
_ => JudgmentType.MISS
};
}

protected virtual int CalculateScoreForHitNoteType(JudgmentType judgmentType)
{
return judgmentType switch
{
JudgmentType.PERFECT => 1000,
JudgmentType.NICE => 500,
JudgmentType.GOOD => 200,
JudgmentType.OK => 100,
_ => 0
};
}

public virtual void Tick(float time)
{
_tick = Utilities.ConvertSecondsToTicks(time, song.Resolution, song.BaseBPM);

Check failure on line 108 in RhythmGameUtilities/Scripts/SongManager.cs

View workflow job for this annotation

GitHub Actions / test-csharp

'Song' does not contain a definition for 'Resolution' and no accessible extension method 'Resolution' accepting a first argument of type 'Song' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 108 in RhythmGameUtilities/Scripts/SongManager.cs

View workflow job for this annotation

GitHub Actions / test-csharp

'Song' does not contain a definition for 'BaseBPM' and no accessible extension method 'BaseBPM' accepting a first argument of type 'Song' could be found (are you missing a using directive or an assembly reference?)
}

public virtual void Cleanup()
{
ClearMissedNotes();
}

}

}
75 changes: 75 additions & 0 deletions RhythmGameUtilities/Structs/Stats.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Newtonsoft.Json;

namespace RhythmGameUtilities
{

public class Stats
{

public const float DefaultComboStep = 0.25f;

public Difficulty difficulty { get; internal set; }

public float comboStep { get; internal set; } = DefaultComboStep;

public int score { get; private set; }

public float combo { get; private set; } = 1;

public int comboMultiplier => (int)Math.Floor(combo);

private readonly Dictionary<JudgmentType, int> _judgmentTypeCount = new();

public ReadOnlyDictionary<JudgmentType, int> judgmentTypeCount => new(_judgmentTypeCount);

public void AddToScore(int points)
{
combo += comboStep;
score += points * comboMultiplier;
}

public void ClearCombo()
{
combo = 1;
}

public void AddJudgment(JudgmentType judgmentType, int count = 1)
{
if (!_judgmentTypeCount.TryAdd(judgmentType, count))
{
_judgmentTypeCount[judgmentType] += count;
}
}

public string ToJSON()
{
return JsonConvert.SerializeObject(this);
}

public static Song FromJSON(string input)
{
return JsonConvert.DeserializeObject<Song>(input);
}

public override string ToString()
{
var output = new StringBuilder();

foreach (var judgment in Enum.GetValues(typeof(JudgmentType)))
{
if (_judgmentTypeCount.TryGetValue((JudgmentType)judgment, out var count))
{
output.AppendLine($"{(JudgmentType)judgment}: {count}");
}
}

return output.ToString().Trim();
}

}

}
19 changes: 19 additions & 0 deletions UnityPackage/Enums/JudgmentType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace RhythmGameUtilities
{

public enum JudgmentType
{

PERFECT,

NICE,

GOOD,

OK,

MISS

}

}
3 changes: 3 additions & 0 deletions UnityPackage/Enums/JudgmentType.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 118 additions & 0 deletions UnityPackage/Scripts/SongManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace RhythmGameUtilities
{

public class SongManager
{

public Stats stats { get; protected set; }

public Song song { get; protected set; }

protected readonly List<Note> _remainingNotes = new();

protected int _tick;

public SongManager(Song song, Difficulty difficulty, float comboStep = Stats.DefaultComboStep)
{
this.song = song;

stats = new Stats { difficulty = difficulty, comboStep = comboStep };

_remainingNotes = GetAllNotes(difficulty).Where(note => note.HandPosition < 5).ToList();
}

public Note[] GetAllNotes(Difficulty difficulty)
{
if (song.Difficulties?[difficulty] == null)
{
throw new InvalidOperationException($"{difficulty} difficulty not found in song!");
}

if (!song.Difficulties.TryGetValue(difficulty, out var notes))
{
throw new InvalidOperationException($"No notes found for the {difficulty} difficulty!");
}

return notes;
}

public List<Note> GetRemainingNotes()
{
return _remainingNotes.ToList();
}

public List<Note> GetActiveNotes(float tickBuffer)
{
var activeNotes = GetRemainingNotes().Where(note =>
_tick > note.Position - tickBuffer / 2 && _tick < note.Position + tickBuffer / 2).ToList();

return activeNotes;
}

protected void ClearMissedNotes()
{
var notesToClear = GetRemainingNotes().Where(note => note.Position + song.BaseBPM / 2 < _tick);

foreach (var note in notesToClear)
{
ClearMissedNote(note);
}
}

protected virtual void ClearMissedNote(Note note)
{
stats.AddJudgment(JudgmentType.MISS);
stats.ClearCombo();
}

protected virtual void HitNoteHandler(Note note, float accuracy, JudgmentType judgmentType)
{
Console.WriteLine($"Hit note with {accuracy} accuracy and a hit note type of {judgmentType}!");
}

protected virtual void MissNoteHandler(Note note)
{
Console.WriteLine("Missed note!");
}

protected virtual JudgmentType CalculateJudgmentTypeFromAccuracy(float accuracy)
{
return accuracy switch
{
> 0.8f => JudgmentType.PERFECT,
> 0.6f => JudgmentType.NICE,
> 0.3f => JudgmentType.GOOD,
> 0 => JudgmentType.OK,
_ => JudgmentType.MISS
};
}

protected virtual int CalculateScoreForHitNoteType(JudgmentType judgmentType)
{
return judgmentType switch
{
JudgmentType.PERFECT => 1000,
JudgmentType.NICE => 500,
JudgmentType.GOOD => 200,
JudgmentType.OK => 100,
_ => 0
};
}

public virtual void Tick(float time)
{
_tick = Utilities.ConvertSecondsToTicks(time, song.Resolution, song.BaseBPM);
}

public virtual void Cleanup()
{
ClearMissedNotes();
}

}

}
3 changes: 3 additions & 0 deletions UnityPackage/Scripts/SongManager.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading