Skip to content

Commit 27e0ffa

Browse files
committed
Reworking and some juice
Reworked note management (again) Set size 2D arrays for notes, that slot in their beat position. Queue-like checking for missed notes Added in game feedback for hit timing quality
1 parent 252a9ac commit 27e0ffa

6 files changed

Lines changed: 108 additions & 51 deletions

File tree

scenes/BattleDirector/BattleDirector.cs

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -44,30 +44,20 @@ public struct SongData
4444
#region Note Handling
4545
//Assume queue structure for notes in each lane.
4646
//Can eventually make this its own structure
47-
private readonly NoteArrow[][] _laneData = new NoteArrow[][]
48-
{
49-
Array.Empty<NoteArrow>(),
50-
Array.Empty<NoteArrow>(),
51-
Array.Empty<NoteArrow>(),
52-
Array.Empty<NoteArrow>(),
47+
private NoteArrow[][] _laneData;
48+
private int[] _laneLastBeat = new int[]
49+
{ //Temporary (hopefully) measure to bridge from note queue structure to ordered array
50+
0,
51+
0,
52+
0,
53+
0,
5354
};
5455
private Note[] _notes = Array.Empty<Note>();
5556

56-
//Cycles lane of dir and returns the, initially, first note
57-
private Note CycleNote(NoteArrow.ArrowType dir)
58-
{
59-
var note = GetFirstNote(dir);
60-
_laneData[(int)dir] = _laneData[(int)dir] //Credit: Stackoverflow https://stackoverflow.com/questions/49494535/moving-the-first-array-element-to-end-in-c-sharp
61-
.Skip(1)
62-
.Concat(_laneData[(int)dir].Take(1))
63-
.ToArray();
64-
return note;
65-
}
66-
6757
//Returns first note of lane without modifying lane data
68-
private Note GetFirstNote(NoteArrow.ArrowType dir)
58+
private Note GetNoteAt(NoteArrow.ArrowType dir, int beat)
6959
{
70-
return GetNote(_laneData[(int)dir].First());
60+
return GetNote(_laneData[(int)dir][beat]);
7161
}
7262

7363
//Get note of a note arrow
@@ -78,6 +68,7 @@ private Note GetNote(NoteArrow arrow)
7868

7969
private bool AddNoteToLane(Note note, bool isActive = true)
8070
{
71+
note.Beat %= CM.BeatsPerLoop;
8172
//Don't add dupe notes
8273
if (_notes.Any(nt => nt.Type == note.Type && nt.Beat == note.Beat))
8374
{
@@ -87,17 +78,18 @@ private bool AddNoteToLane(Note note, bool isActive = true)
8778
//Get noteArrow from CM
8879
var arrow = CM.AddArrowToLane(note, _notes.Length - 1);
8980
arrow.IsActive = isActive;
90-
_laneData[(int)note.Type] = _laneData[(int)note.Type].Append(arrow).ToArray();
81+
_laneData[(int)note.Type][note.Beat] = arrow;
9182
return true;
9283
}
9384
#endregion
9485

9586
//Creeate dummy notes
9687
private void AddExampleNotes()
9788
{
89+
GD.Print(CM.BeatsPerLoop);
9890
for (int i = 0; i < 1; i++)
9991
{
100-
Note exampleNote = new Note(NoteArrow.ArrowType.Down, i + 5);
92+
Note exampleNote = new Note(NoteArrow.ArrowType.Down, i);
10193
AddNoteToLane(exampleNote);
10294
}
10395
for (int i = 0; i < 4; i++)
@@ -107,7 +99,7 @@ private void AddExampleNotes()
10799
}
108100
for (int i = 0; i < 1; i++)
109101
{
110-
Note exampleNote = new Note(NoteArrow.ArrowType.Left, i + 21);
102+
Note exampleNote = new Note(NoteArrow.ArrowType.Left, CM.BeatsPerLoop);
111103
AddNoteToLane(exampleNote);
112104
}
113105
}
@@ -121,6 +113,13 @@ public override void _Ready()
121113
NumLoops = 5,
122114
};
123115
CM.PrepChart(_curSong);
116+
_laneData = new NoteArrow[][]
117+
{
118+
new NoteArrow[CM.BeatsPerLoop],
119+
new NoteArrow[CM.BeatsPerLoop],
120+
new NoteArrow[CM.BeatsPerLoop],
121+
new NoteArrow[CM.BeatsPerLoop],
122+
};
124123
AddExampleNotes();
125124

126125
Player = GetNode<HealthBar>("PlayerHP");
@@ -162,65 +161,81 @@ private void OnNoteReleased(NoteArrow.ArrowType arrowType) { }
162161
//Check all lanes for misses from missed inputs
163162
private void CheckMiss()
164163
{
165-
double curBeat = TimeKeeper.CurrentTime / (60 / (double)_curSong.Bpm) % CM.BeatsPerLoop;
164+
//On current beat, if prev beat is active and not inputted
165+
double realBeat = TimeKeeper.CurrentTime / (60 / (double)_curSong.Bpm) % CM.BeatsPerLoop;
166166
for (int i = 0; i < _laneData.Length; i++)
167167
{
168-
if (_laneData[i].Length <= 0)
169-
continue;
170-
double beatDif = (curBeat - GetFirstNote((NoteArrow.ArrowType)i).Beat);
171-
if (beatDif > 1 && _laneData[i].First().IsActive)
172-
{
173-
_laneData[i].First().NoteHit();
174-
HandleTiming((NoteArrow.ArrowType)i, Math.Abs(beatDif));
168+
if (
169+
_laneLastBeat[i] < Math.Floor(realBeat)
170+
|| (_laneLastBeat[i] == CM.BeatsPerLoop - 1 && Math.Floor(realBeat) == 0)
171+
)
172+
{ //If above, a note has been missed
173+
//GD.Print("Last beat " + _laneLastBeat[i]);
174+
if (
175+
_laneData[i][_laneLastBeat[i]] == null
176+
|| !_laneData[i][_laneLastBeat[i]].IsActive
177+
)
178+
{
179+
_laneLastBeat[i] = (_laneLastBeat[i] + 1) % CM.BeatsPerLoop;
180+
continue;
181+
}
182+
//Note exists and has been missed
183+
_laneData[i][_laneLastBeat[i]].NoteHit();
184+
HandleTiming((NoteArrow.ArrowType)i, 1);
185+
_laneLastBeat[i] = (_laneLastBeat[i] + 1) % CM.BeatsPerLoop;
175186
}
176187
}
177188
}
178189

179190
private void CheckNoteTiming(NoteArrow.ArrowType type)
180191
{
181-
double curBeat = TimeKeeper.CurrentTime / (60 / (double)_curSong.Bpm) % CM.BeatsPerLoop;
182-
if (_laneData[(int)type].Length == 0)
183-
{
184-
PlayerAddNote(type, (int)Math.Round(curBeat));
185-
return;
186-
}
187-
double beatDif = Math.Abs(curBeat - GetFirstNote(type).Beat);
188-
if (beatDif > 1)
192+
double realBeat = TimeKeeper.CurrentTime / (60 / (double)_curSong.Bpm) % CM.BeatsPerLoop;
193+
int curBeat = (int)Math.Round(realBeat);
194+
GD.Print("Cur beat " + curBeat + "Real: " + realBeat.ToString("#.###"));
195+
if (
196+
_laneData[(int)type][curBeat % CM.BeatsPerLoop] == null
197+
|| !_laneData[(int)type][curBeat % CM.BeatsPerLoop].IsActive
198+
)
189199
{
190-
PlayerAddNote(type, (int)Math.Round(curBeat));
200+
_laneLastBeat[(int)type] = (curBeat) % CM.BeatsPerLoop;
201+
PlayerAddNote(type, curBeat);
191202
return;
192203
}
193-
GD.Print("Note Hit. Dif: " + beatDif);
194-
_laneData[(int)type].First().NoteHit();
204+
double beatDif = Math.Abs(realBeat - curBeat);
205+
_laneData[(int)type][curBeat % CM.BeatsPerLoop].NoteHit();
206+
_laneLastBeat[(int)type] = (curBeat) % CM.BeatsPerLoop;
195207
HandleTiming(type, beatDif);
196208
}
197209

198210
private void HandleTiming(NoteArrow.ArrowType type, double beatDif)
199211
{
200-
CycleNote(type);
201-
if (beatDif < _timingInterval * 2)
212+
if (beatDif < _timingInterval * 1)
202213
{
203214
GD.Print("Perfect");
204215
Enemy.TakeDamage(1);
205216
NotePlacementBar.HitNote();
217+
NotePlacementBar.ComboText("Perfect!");
206218
}
207-
else if (beatDif < _timingInterval * 4)
219+
else if (beatDif < _timingInterval * 2)
208220
{
209221
GD.Print("Good");
210222
Enemy.TakeDamage(0);
211223
NotePlacementBar.HitNote();
224+
NotePlacementBar.ComboText("Good");
212225
}
213-
else if (beatDif < _timingInterval * 6)
226+
else if (beatDif < _timingInterval * 3)
214227
{
215-
GD.Print("Okay");
228+
GD.Print("Ok");
216229
Player.TakeDamage(1);
217230
NotePlacementBar.HitNote();
231+
NotePlacementBar.ComboText("Okay");
218232
}
219233
else
220234
{
221235
GD.Print("Miss");
222236
Player.TakeDamage(2);
223237
NotePlacementBar.MissNote();
238+
NotePlacementBar.ComboText("Miss");
224239
}
225240
}
226241
#endregion

scenes/BattleDirector/NotePlacementBar.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
public partial class NotePlacementBar : Node
55
{
6-
const int MaxValue = 50;
6+
const int MaxValue = 5;
77
int currentBarValue;
88
int currentCombo;
99
int comboMult;
@@ -25,6 +25,16 @@ public override void _Ready()
2525
notesToIncreaseCombo = 4;
2626
}
2727

28+
public void ComboText(string text)
29+
{
30+
var feedbackScene = ResourceLoader.Load<PackedScene>(
31+
"res://scenes/BattleDirector/TextParticle.tscn"
32+
);
33+
TextParticle newText = feedbackScene.Instantiate<TextParticle>();
34+
AddChild(newText);
35+
newText.Text = text + $" {currentCombo}";
36+
}
37+
2838
// Hitting a note increases combo, combo mult, and note placement bar
2939
public void HitNote()
3040
{
@@ -52,9 +62,7 @@ public void PlacedNote()
5262

5363
public bool CanPlaceNote()
5464
{
55-
if (currentBarValue >= MaxValue)
56-
return true;
57-
return false;
65+
return currentBarValue >= MaxValue;
5866
}
5967

6068
private void DetermineComboMult()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using Godot;
3+
4+
public partial class TextParticle : Label
5+
{
6+
// Called when the node enters the scene tree for the first time.
7+
public override void _Ready()
8+
{
9+
Tween tween = GetTree().CreateTween();
10+
tween.SetTrans(Tween.TransitionType.Quad);
11+
tween.SetEase(Tween.EaseType.Out);
12+
tween.TweenProperty(this, "position", Position + Vector2.Up * 10, .5f);
13+
tween.TweenProperty(this, "position", Position + Vector2.Down * 20, .5f);
14+
tween.SetParallel();
15+
tween.TweenProperty(this, "modulate:a", 0, 1f);
16+
tween.SetParallel(false);
17+
tween.TweenCallback(Callable.From(QueueFree));
18+
}
19+
20+
// Called every frame. 'delta' is the elapsed time since the previous frame.
21+
public override void _Process(double delta) { }
22+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[gd_scene load_steps=2 format=3 uid="uid://bd23wwbv7i4gg"]
2+
3+
[ext_resource type="Script" path="res://scenes/BattleDirector/TextParticle.cs" id="1_j0ufq"]
4+
5+
[node name="Control" type="Label"]
6+
anchors_preset = -1
7+
anchor_right = 0.08
8+
text = "900000"
9+
script = ExtResource("1_j0ufq")

scenes/BattleDirector/test_battle_scene.tscn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,5 @@ offset_left = 12.0
6767
offset_top = 145.0
6868
offset_right = 12.0
6969
offset_bottom = 145.0
70+
71+
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]

scenes/ChartViewport/ChartManager.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public partial class ChartManager : SubViewportContainer
2525
public delegate void NoteReleasedEventHandler(ArrowType arrowType);
2626

2727
//Arbitrary vars, play with these
28-
private double ChartLength = 2400; //Might move this to be song specific?
28+
private double ChartLength = 5000; //Might move this to be song specific?
2929
private double _loopLen; //secs
3030
public int BeatsPerLoop;
3131

@@ -113,6 +113,7 @@ private NoteArrow CreateNote(ArrowType arrow, int beat = 0)
113113

114114
_arrowGroup.AddChild(newArrow);
115115
newArrow.Bounds = (float)((double)beat / BeatsPerLoop * (ChartLength / 2));
116+
newArrow.Position += Vector2.Right * newArrow.Bounds; //temporary fix for notes spawning and instantly calling loop from originating at 0,0
116117
return newArrow;
117118
}
118119
}

0 commit comments

Comments
 (0)