Skip to content

Commit c5cf3b3

Browse files
authored
Merge pull request #38 from Project-Funk-Engine/rewrite
Finalized sprint 1 version
2 parents 993b9c1 + bba4b9c commit c5cf3b3

23 files changed

Lines changed: 597 additions & 223 deletions
2.44 MB
Binary file not shown.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[remap]
2+
3+
importer="mp3"
4+
type="AudioStreamMP3"
5+
uid="uid://cv6lqjj6lu36h"
6+
path="res://.godot/imported/335571__magntron__gamemusic_120bpm.mp3-a87b357c4b3c9199709863b47f78bd2a.mp3str"
7+
8+
[deps]
9+
10+
source_file="res://Audio/335571__magntron__gamemusic_120bpm.mp3"
11+
dest_files=["res://.godot/imported/335571__magntron__gamemusic_120bpm.mp3-a87b357c4b3c9199709863b47f78bd2a.mp3str"]
12+
13+
[params]
14+
15+
loop=true
16+
loop_offset=0
17+
bpm=0
18+
beat_count=0
19+
bar_beats=4

Funk Engine.sln.DotSettings.user

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2-
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fgamef_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F6354a7b35d7821629924d3676acd7e67a6f7f94343e0e66ec439aa2bd6ed5_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
2+
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003FUsers_003Fgamef_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F6354a7b35d7821629924d3676acd7e67a6f7f94343e0e66ec439aa2bd6ed5_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
3+
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F6354a7b35d7821629924d3676acd7e67a6f7f94343e0e66ec439aa2bd6ed5_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>

scenes/BattleDirector/BattleDirector.cs

Lines changed: 177 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,22 @@
1010
*/
1111
public partial class BattleDirector : Node2D
1212
{
13-
[Export]
14-
public ChartManager CM;
13+
#region Declarations
14+
private HealthBar Player;
15+
private HealthBar Enemy;
1516

1617
[Export]
17-
public NoteManager NM;
18+
private ChartManager CM;
1819

19-
private HealthBar Player;
20-
private HealthBar Enemy;
20+
[Export]
21+
private InputHandler IH;
2122

23+
[Export]
2224
private NotePlacementBar NotePlacementBar;
2325

26+
[Export]
27+
private AudioStreamPlayer Audio;
28+
2429
private double _timingInterval = .1; //secs
2530

2631
[Signal]
@@ -29,148 +34,231 @@ public partial class BattleDirector : Node2D
2934
[Signal]
3035
public delegate void EnemyDamageEventHandler(int damage);
3136

37+
private SongData _curSong;
38+
3239
public struct SongData
3340
{
3441
public int Bpm;
3542
public double SongLength;
3643
public int NumLoops;
3744
}
45+
#endregion
3846

39-
private SongData _curSong;
40-
47+
#region Note Handling
4148
//Assume queue structure for notes in each lane.
42-
private readonly Note[][] _laneNotes = new Note[][]
43-
{
44-
Array.Empty<Note>(),
45-
Array.Empty<Note>(),
46-
Array.Empty<Note>(),
47-
Array.Empty<Note>(),
49+
//Can eventually make this its own structure
50+
private NoteArrow[][] _laneData = Array.Empty<NoteArrow[]>();
51+
private int[] _laneLastBeat = new int[]
52+
{ //Temporary (hopefully) measure to bridge from note queue structure to ordered array
53+
0,
54+
0,
55+
0,
56+
0,
4857
};
4958
private Note[] _notes = Array.Empty<Note>();
5059

51-
public override void _Ready()
60+
//Returns first note of lane without modifying lane data
61+
private Note GetNoteAt(NoteArrow.ArrowType dir, int beat)
5262
{
53-
AddExampleNote();
54-
CM.PrepChart(_curSong, _notes);
55-
56-
Player = GetNode<HealthBar>("PlayerHP");
57-
Enemy = GetNode<HealthBar>("EnemyHP");
58-
NotePlacementBar = GetNode<NotePlacementBar>("NotePlacementBar");
63+
return GetNote(_laneData[(int)dir][beat]);
64+
}
5965

60-
CM.Connect(nameof(NoteManager.NotePressed), new Callable(this, nameof(OnNotePressed)));
61-
CM.Connect(nameof(NoteManager.NoteReleased), new Callable(this, nameof(OnNoteReleased)));
66+
//Get note of a note arrow
67+
private Note GetNote(NoteArrow arrow)
68+
{
69+
return _notes[arrow.NoteIdx];
6270
}
6371

64-
public override void _Process(double delta)
72+
private bool AddNoteToLane(Note note, bool isActive = true)
6573
{
66-
TimeKeeper.CurrentTime += delta;
67-
//Check beats for each lane for passive misses
68-
double curBeat = TimeKeeper.CurrentTime / (60 / (double)_curSong.Bpm);
69-
for (int i = 0; i < _laneNotes.Length; i++)
74+
note.Beat %= CM.BeatsPerLoop;
75+
//Don't add dupe notes
76+
if (note.Beat == 0 || _notes.Any(nt => nt.Type == note.Type && nt.Beat == note.Beat))
7077
{
71-
if (_laneNotes[i].Length <= 0)
72-
continue;
73-
double beatDif = (curBeat - _laneNotes[i].First().Beat);
74-
if (beatDif > 1)
75-
{
76-
handleTiming((NoteArrow.ArrowType)i, Math.Abs(beatDif));
77-
}
78+
return false; //Beat at 0 is too messy.
7879
}
80+
_notes = _notes.Append(note).ToArray();
81+
//Get noteArrow from CM
82+
var arrow = CM.AddArrowToLane(note, _notes.Length - 1);
83+
arrow.IsActive = isActive;
84+
_laneData[(int)note.Type][note.Beat] = arrow;
85+
return true;
7986
}
87+
#endregion
8088

81-
//Creeate dummy song data and notes
82-
private void AddExampleNote()
89+
//Creeate dummy notes
90+
private void AddExampleNotes()
8391
{
84-
_curSong = new SongData
92+
GD.Print(CM.BeatsPerLoop);
93+
for (int i = 1; i < 15; i++)
8594
{
86-
Bpm = 120,
87-
SongLength = 100,
88-
NumLoops = 5,
89-
};
90-
for (int i = 0; i < 4; i++)
95+
Note exampleNote = new Note(NoteArrow.ArrowType.Up, i * 4);
96+
AddNoteToLane(exampleNote);
97+
}
98+
for (int i = 1; i < 15; i++)
99+
{
100+
Note exampleNote = new Note(NoteArrow.ArrowType.Left, 4 * i + 1);
101+
AddNoteToLane(exampleNote);
102+
}
103+
for (int i = 0; i < 10; i++)
91104
{
92-
Note exampleNote = new Note(NoteArrow.ArrowType.Up, i + 3);
105+
Note exampleNote = new Note(NoteArrow.ArrowType.Right, 3 * i + 32);
93106
AddNoteToLane(exampleNote);
94107
}
95-
for (int i = 0; i < 1; i++)
108+
for (int i = 0; i < 3; i++)
96109
{
97-
Note exampleNote = new Note(NoteArrow.ArrowType.Left, i + 4);
110+
Note exampleNote = new Note(NoteArrow.ArrowType.Down, 8 * i + 16);
98111
AddNoteToLane(exampleNote);
99112
}
100113
}
101114

102-
private void AddNoteToLane(Note note)
115+
public override void _Ready()
103116
{
104-
_notes = _notes.Append(note).ToArray();
105-
_laneNotes[(int)note.Type] = _laneNotes[(int)note.Type].Append(note).ToArray();
117+
_curSong = new SongData
118+
{
119+
Bpm = 120,
120+
SongLength = Audio.Stream.GetLength(),
121+
NumLoops = 5,
122+
};
123+
124+
var timer = GetTree().CreateTimer(AudioServer.GetTimeToNextMix());
125+
timer.Timeout += Begin;
106126
}
107127

128+
private void Begin()
129+
{
130+
CM.PrepChart(_curSong);
131+
_laneData = new NoteArrow[][]
132+
{
133+
new NoteArrow[CM.BeatsPerLoop],
134+
new NoteArrow[CM.BeatsPerLoop],
135+
new NoteArrow[CM.BeatsPerLoop],
136+
new NoteArrow[CM.BeatsPerLoop],
137+
};
138+
AddExampleNotes();
139+
140+
Player = GetNode<HealthBar>("PlayerHP");
141+
Player.GetNode<Sprite2D>("Sprite2D").Scale *= .5f; //TEMP
142+
Player.GetNode<Sprite2D>("Sprite2D").Position += Vector2.Down * 30; //TEMP
143+
Enemy = GetNode<HealthBar>("EnemyHP");
144+
145+
//TEMP
146+
var enemTween = CreateTween();
147+
enemTween
148+
.TweenProperty(Enemy.GetNode<Sprite2D>("Sprite2D"), "position", Vector2.Down * 5, 1f)
149+
.AsRelative();
150+
enemTween
151+
.TweenProperty(Enemy.GetNode<Sprite2D>("Sprite2D"), "position", Vector2.Up * 5, 1f)
152+
.AsRelative();
153+
enemTween.SetTrans(Tween.TransitionType.Spring);
154+
enemTween.SetEase(Tween.EaseType.In);
155+
enemTween.SetLoops();
156+
enemTween.Play();
157+
158+
CM.Connect(nameof(InputHandler.NotePressed), new Callable(this, nameof(OnNotePressed)));
159+
CM.Connect(nameof(InputHandler.NoteReleased), new Callable(this, nameof(OnNoteReleased)));
160+
161+
Audio.Play();
162+
}
163+
164+
public override void _Process(double delta)
165+
{
166+
TimeKeeper.CurrentTime = Audio.GetPlaybackPosition();
167+
CheckMiss();
168+
}
169+
170+
#region Input&Timing
108171
private void OnNotePressed(NoteArrow.ArrowType type)
109172
{
110173
CheckNoteTiming(type);
111174
}
112175

113176
private void OnNoteReleased(NoteArrow.ArrowType arrowType) { }
114177

115-
private void handleTiming(NoteArrow.ArrowType type, double beatDif)
178+
//Check all lanes for misses from missed inputs
179+
private void CheckMiss()
180+
{
181+
//On current beat, if prev beat is active and not inputted
182+
double realBeat = TimeKeeper.CurrentTime / (60 / (double)_curSong.Bpm) % CM.BeatsPerLoop;
183+
for (int i = 0; i < _laneData.Length; i++)
184+
{
185+
if (
186+
_laneLastBeat[i] < Math.Floor(realBeat)
187+
|| (_laneLastBeat[i] == CM.BeatsPerLoop - 1 && Math.Floor(realBeat) == 0)
188+
)
189+
{ //If above, a note has been missed
190+
//GD.Print("Last beat " + _laneLastBeat[i]);
191+
if (
192+
_laneData[i][_laneLastBeat[i]] == null
193+
|| !_laneData[i][_laneLastBeat[i]].IsActive
194+
)
195+
{
196+
_laneLastBeat[i] = (_laneLastBeat[i] + 1) % CM.BeatsPerLoop;
197+
continue;
198+
}
199+
//Note exists and has been missed
200+
_laneData[i][_laneLastBeat[i]].NoteHit();
201+
HandleTiming((NoteArrow.ArrowType)i, 1);
202+
_laneLastBeat[i] = (_laneLastBeat[i] + 1) % CM.BeatsPerLoop;
203+
}
204+
}
205+
}
206+
207+
private void CheckNoteTiming(NoteArrow.ArrowType type)
208+
{
209+
double realBeat = TimeKeeper.CurrentTime / (60 / (double)_curSong.Bpm) % CM.BeatsPerLoop;
210+
int curBeat = (int)Math.Round(realBeat);
211+
GD.Print("Cur beat " + curBeat + "Real: " + realBeat.ToString("#.###"));
212+
if (
213+
_laneData[(int)type][curBeat % CM.BeatsPerLoop] == null
214+
|| !_laneData[(int)type][curBeat % CM.BeatsPerLoop].IsActive
215+
)
216+
{
217+
_laneLastBeat[(int)type] = (curBeat) % CM.BeatsPerLoop;
218+
PlayerAddNote(type, curBeat);
219+
return;
220+
}
221+
double beatDif = Math.Abs(realBeat - curBeat);
222+
_laneData[(int)type][curBeat % CM.BeatsPerLoop].NoteHit();
223+
_laneLastBeat[(int)type] = (curBeat) % CM.BeatsPerLoop;
224+
HandleTiming(type, beatDif);
225+
}
226+
227+
private void HandleTiming(NoteArrow.ArrowType type, double beatDif)
116228
{
117-
//Cycle note queue
118-
_laneNotes[(int)type].First().Beat += CM.BeatsPerLoop;
119-
_laneNotes[(int)type] = _laneNotes[(int)type] //Credit: Stackoverflow https://stackoverflow.com/questions/49494535/moving-the-first-array-element-to-end-in-c-sharp
120-
.Skip(1)
121-
.Concat(_laneNotes[(int)type].Take(1))
122-
.ToArray(); //TODO: No stackoverflow code
123-
//Do timing stuff
124-
if (beatDif < _timingInterval * 2)
229+
if (beatDif < _timingInterval * 1)
125230
{
126231
GD.Print("Perfect");
127-
Enemy.TakeDamage(10);
232+
Enemy.TakeDamage(3);
128233
NotePlacementBar.HitNote();
234+
NotePlacementBar.ComboText("Perfect!");
129235
}
130-
else if (beatDif < _timingInterval * 4)
236+
else if (beatDif < _timingInterval * 2)
131237
{
132238
GD.Print("Good");
133-
Enemy.TakeDamage(5);
239+
Enemy.TakeDamage(1);
134240
NotePlacementBar.HitNote();
241+
NotePlacementBar.ComboText("Good");
135242
}
136-
else if (beatDif < _timingInterval * 6)
243+
else if (beatDif < _timingInterval * 3)
137244
{
138-
GD.Print("Okay");
139-
Enemy.TakeDamage(1);
245+
GD.Print("Ok");
246+
Player.TakeDamage(1);
140247
NotePlacementBar.HitNote();
248+
NotePlacementBar.ComboText("Okay");
141249
}
142250
else
143251
{
144252
GD.Print("Miss");
145-
Player.TakeDamage(10);
253+
Player.TakeDamage(2);
146254
NotePlacementBar.MissNote();
255+
NotePlacementBar.ComboText("Miss");
147256
}
148257
}
149-
150-
private void CheckNoteTiming(NoteArrow.ArrowType type)
151-
{
152-
double curBeat = TimeKeeper.CurrentTime / (60 / (double)_curSong.Bpm);
153-
if (_laneNotes[(int)type].Length == 0)
154-
{
155-
PlayerAddNote(type, (int)curBeat);
156-
return;
157-
}
158-
double beatDif = Math.Abs(curBeat - _laneNotes[(int)type].First().Beat);
159-
if (beatDif > 1)
160-
{
161-
PlayerAddNote(type, (int)curBeat);
162-
return;
163-
}
164-
GD.Print("Note Hit. Dif: " + beatDif);
165-
CM.HandleNote(type);
166-
handleTiming(type, beatDif);
167-
}
258+
#endregion
168259

169260
private void PlayerAddNote(NoteArrow.ArrowType type, int beat)
170261
{
171-
//TODO: notes currently can only be placed in first loop.
172-
// placed notes are also non-interactable
173-
174262
// can also add some sort of keybind here to also have pressed
175263
// in case the user just presses the note too early and spawns a note
176264
GD.Print(
@@ -181,8 +269,9 @@ private void PlayerAddNote(NoteArrow.ArrowType type, int beat)
181269
);
182270
if (NotePlacementBar.CanPlaceNote())
183271
{
184-
CM.CreateNote(type, beat);
185-
NotePlacementBar.PlacedNote();
272+
Note exampleNote = new Note(type, beat % CM.BeatsPerLoop);
273+
if (AddNoteToLane(exampleNote, false))
274+
NotePlacementBar.PlacedNote();
186275
}
187276
}
188277
}

0 commit comments

Comments
 (0)