Skip to content

Commit 6bfb113

Browse files
committed
Added SongManager class.
1 parent 3ecac19 commit 6bfb113

File tree

9 files changed

+433
-0
lines changed

9 files changed

+433
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace RhythmGameUtilities
2+
{
3+
4+
public enum JudgmentType
5+
{
6+
7+
PERFECT,
8+
9+
NICE,
10+
11+
GOOD,
12+
13+
OK,
14+
15+
MISS
16+
17+
}
18+
19+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace RhythmGameUtilities
6+
{
7+
8+
public class SongManager
9+
{
10+
11+
public Stats stats { get; protected set; }
12+
13+
public Song song { get; protected set; }
14+
15+
protected readonly List<Note> _remainingNotes = new();
16+
17+
protected int _tick;
18+
19+
public SongManager(Song song, Difficulty difficulty, float comboStep = Stats.DefaultComboStep)
20+
{
21+
this.song = song;
22+
23+
stats = new Stats { difficulty = difficulty, comboStep = comboStep };
24+
25+
_remainingNotes = GetAllNotes(difficulty).Where(note => note.HandPosition < 5).ToList();
26+
}
27+
28+
public Note[] GetAllNotes(Difficulty difficulty)
29+
{
30+
if (song.Difficulties?[difficulty] == null)
31+
{
32+
throw new InvalidOperationException($"{difficulty} difficulty not found in song!");
33+
}
34+
35+
if (!song.Difficulties.TryGetValue(difficulty, out var notes))
36+
{
37+
throw new InvalidOperationException($"No notes found for the {difficulty} difficulty!");
38+
}
39+
40+
return notes;
41+
}
42+
43+
public List<Note> GetRemainingNotes()
44+
{
45+
return _remainingNotes.ToList();
46+
}
47+
48+
public List<Note> GetActiveNotes(float tickBuffer)
49+
{
50+
var activeNotes = GetRemainingNotes().Where(note =>
51+
_tick > note.Position - tickBuffer / 2 && _tick < note.Position + tickBuffer / 2).ToList();
52+
53+
return activeNotes;
54+
}
55+
56+
protected void ClearMissedNotes()
57+
{
58+
var notesToClear = GetRemainingNotes().Where(note => note.Position + song.BaseBPM / 2 < _tick);
59+
60+
foreach (var note in notesToClear)
61+
{
62+
ClearMissedNote(note);
63+
}
64+
}
65+
66+
protected virtual void ClearMissedNote(Note note)
67+
{
68+
stats.AddJudgment(JudgmentType.MISS);
69+
stats.ClearCombo();
70+
}
71+
72+
protected virtual void HitNoteHandler(Note note, float accuracy, JudgmentType judgmentType)
73+
{
74+
Console.WriteLine($"Hit note with {accuracy} accuracy and a hit note type of {judgmentType}!");
75+
}
76+
77+
protected virtual void MissNoteHandler(Note note)
78+
{
79+
Console.WriteLine("Missed note!");
80+
}
81+
82+
protected virtual JudgmentType CalculateJudgmentTypeFromAccuracy(float accuracy)
83+
{
84+
return accuracy switch
85+
{
86+
> 0.8f => JudgmentType.PERFECT,
87+
> 0.6f => JudgmentType.NICE,
88+
> 0.3f => JudgmentType.GOOD,
89+
> 0 => JudgmentType.OK,
90+
_ => JudgmentType.MISS
91+
};
92+
}
93+
94+
protected virtual int CalculateScoreForHitNoteType(JudgmentType judgmentType)
95+
{
96+
return judgmentType switch
97+
{
98+
JudgmentType.PERFECT => 1000,
99+
JudgmentType.NICE => 500,
100+
JudgmentType.GOOD => 200,
101+
JudgmentType.OK => 100,
102+
_ => 0
103+
};
104+
}
105+
106+
public virtual void Tick(float time)
107+
{
108+
_tick = Utilities.ConvertSecondsToTicks(time, song.Resolution, song.BaseBPM);
109+
}
110+
111+
public virtual void Cleanup()
112+
{
113+
ClearMissedNotes();
114+
}
115+
116+
}
117+
118+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.Text;
5+
using Newtonsoft.Json;
6+
7+
namespace RhythmGameUtilities
8+
{
9+
10+
public class Stats
11+
{
12+
13+
public const float DefaultComboStep = 0.25f;
14+
15+
public Difficulty difficulty { get; internal set; }
16+
17+
public float comboStep { get; internal set; } = DefaultComboStep;
18+
19+
public int score { get; private set; }
20+
21+
public float combo { get; private set; } = 1;
22+
23+
public int comboMultiplier => (int)Math.Floor(combo);
24+
25+
private readonly Dictionary<JudgmentType, int> _judgmentTypeCount = new();
26+
27+
public ReadOnlyDictionary<JudgmentType, int> judgmentTypeCount => new(_judgmentTypeCount);
28+
29+
public void AddToScore(int points)
30+
{
31+
combo += comboStep;
32+
score += points * comboMultiplier;
33+
}
34+
35+
public void ClearCombo()
36+
{
37+
combo = 1;
38+
}
39+
40+
public void AddJudgment(JudgmentType judgmentType, int count = 1)
41+
{
42+
if (!_judgmentTypeCount.TryAdd(judgmentType, count))
43+
{
44+
_judgmentTypeCount[judgmentType] += count;
45+
}
46+
}
47+
48+
public string ToJSON()
49+
{
50+
return JsonConvert.SerializeObject(this);
51+
}
52+
53+
public static Song FromJSON(string input)
54+
{
55+
return JsonConvert.DeserializeObject<Song>(input);
56+
}
57+
58+
public override string ToString()
59+
{
60+
var output = new StringBuilder();
61+
62+
foreach (var judgment in Enum.GetValues(typeof(JudgmentType)))
63+
{
64+
if (_judgmentTypeCount.TryGetValue((JudgmentType)judgment, out var count))
65+
{
66+
output.AppendLine($"{(JudgmentType)judgment}: {count}");
67+
}
68+
}
69+
70+
return output.ToString().Trim();
71+
}
72+
73+
}
74+
75+
}

UnityPackage/Enums/JudgmentType.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace RhythmGameUtilities
2+
{
3+
4+
public enum JudgmentType
5+
{
6+
7+
PERFECT,
8+
9+
NICE,
10+
11+
GOOD,
12+
13+
OK,
14+
15+
MISS
16+
17+
}
18+
19+
}

UnityPackage/Enums/JudgmentType.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace RhythmGameUtilities
6+
{
7+
8+
public class SongManager
9+
{
10+
11+
public Stats stats { get; protected set; }
12+
13+
public Song song { get; protected set; }
14+
15+
protected readonly List<Note> _remainingNotes = new();
16+
17+
protected int _tick;
18+
19+
public SongManager(Song song, Difficulty difficulty, float comboStep = Stats.DefaultComboStep)
20+
{
21+
this.song = song;
22+
23+
stats = new Stats { difficulty = difficulty, comboStep = comboStep };
24+
25+
_remainingNotes = GetAllNotes(difficulty).Where(note => note.HandPosition < 5).ToList();
26+
}
27+
28+
public Note[] GetAllNotes(Difficulty difficulty)
29+
{
30+
if (song.Difficulties?[difficulty] == null)
31+
{
32+
throw new InvalidOperationException($"{difficulty} difficulty not found in song!");
33+
}
34+
35+
if (!song.Difficulties.TryGetValue(difficulty, out var notes))
36+
{
37+
throw new InvalidOperationException($"No notes found for the {difficulty} difficulty!");
38+
}
39+
40+
return notes;
41+
}
42+
43+
public List<Note> GetRemainingNotes()
44+
{
45+
return _remainingNotes.ToList();
46+
}
47+
48+
public List<Note> GetActiveNotes(float tickBuffer)
49+
{
50+
var activeNotes = GetRemainingNotes().Where(note =>
51+
_tick > note.Position - tickBuffer / 2 && _tick < note.Position + tickBuffer / 2).ToList();
52+
53+
return activeNotes;
54+
}
55+
56+
protected void ClearMissedNotes()
57+
{
58+
var notesToClear = GetRemainingNotes().Where(note => note.Position + song.BaseBPM / 2 < _tick);
59+
60+
foreach (var note in notesToClear)
61+
{
62+
ClearMissedNote(note);
63+
}
64+
}
65+
66+
protected virtual void ClearMissedNote(Note note)
67+
{
68+
stats.AddJudgment(JudgmentType.MISS);
69+
stats.ClearCombo();
70+
}
71+
72+
protected virtual void HitNoteHandler(Note note, float accuracy, JudgmentType judgmentType)
73+
{
74+
Console.WriteLine($"Hit note with {accuracy} accuracy and a hit note type of {judgmentType}!");
75+
}
76+
77+
protected virtual void MissNoteHandler(Note note)
78+
{
79+
Console.WriteLine("Missed note!");
80+
}
81+
82+
protected virtual JudgmentType CalculateJudgmentTypeFromAccuracy(float accuracy)
83+
{
84+
return accuracy switch
85+
{
86+
> 0.8f => JudgmentType.PERFECT,
87+
> 0.6f => JudgmentType.NICE,
88+
> 0.3f => JudgmentType.GOOD,
89+
> 0 => JudgmentType.OK,
90+
_ => JudgmentType.MISS
91+
};
92+
}
93+
94+
protected virtual int CalculateScoreForHitNoteType(JudgmentType judgmentType)
95+
{
96+
return judgmentType switch
97+
{
98+
JudgmentType.PERFECT => 1000,
99+
JudgmentType.NICE => 500,
100+
JudgmentType.GOOD => 200,
101+
JudgmentType.OK => 100,
102+
_ => 0
103+
};
104+
}
105+
106+
public virtual void Tick(float time)
107+
{
108+
_tick = Utilities.ConvertSecondsToTicks(time, song.Resolution, song.BaseBPM);
109+
}
110+
111+
public virtual void Cleanup()
112+
{
113+
ClearMissedNotes();
114+
}
115+
116+
}
117+
118+
}

UnityPackage/Scripts/SongManager.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)