-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNotePlacementBar.cs
More file actions
315 lines (272 loc) · 8.41 KB
/
NotePlacementBar.cs
File metadata and controls
315 lines (272 loc) · 8.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
using System;
using System.Collections.Generic;
using FunkEngine;
using Godot;
/**<summary>Current charge bar amount and note queue.</summary>
*/
public partial class NotePlacementBar : Node
{ //TODO: More effectively integrate with player
private double MaxValue
{
get => _notePlacementBar.MaxValue;
set
{
_notePlacementBar.MaxValue = value;
_particles.Emitting = CurrentBarValue >= MaxValue;
}
}
private double CurrentBarValue
{
get => _notePlacementBar.Value;
set
{
_notePlacementBar.Value = value;
_particles.Emitting = CurrentBarValue >= MaxValue; //This is so goated
_waveMaterial.SetShaderParameter("fillLevel", _notePlacementBar.Value / MaxValue);
}
}
[Export]
private ShaderMaterial _waveMaterial; //Sort of breaks the pixel art style, but its cool
[Export]
private TextureProgressBar _notePlacementBar;
private Gradient _gradTex;
[Export]
private GpuParticles2D _particles;
[Export]
private CpuParticles2D _fullBarParticles;
private Note[] _noteDeck;
#region Combo&Mult
[Export]
private TextEdit _currentComboMultText;
private int _currentCombo;
private int MaxComboMult;
private int ComboMult =>
Math.Min(_currentCombo / _notesToIncreaseCombo + 1 + _bonusMult, MaxComboMult);
private int _bonusMult;
private int _notesToIncreaseCombo;
private void UpdateComboMultText()
{
_currentComboMultText.Text = $" x{ComboMult.ToString()}";
}
#endregion
#region Initialization
public override void _Ready()
{
MaxValue = 60;
_notesToIncreaseCombo = 4;
_barInitPosition = _notePlacementBar.Position;
if (_notePlacementBar.TextureProgress is GradientTexture2D gradientTexture)
_gradTex = gradientTexture.Gradient;
_waveMaterial.SetShaderParameter("fillLevel", 0.0);
}
public override void _Process(double delta)
{
ProcessShake(delta);
}
public void Setup(PlayerStats playerStats)
{
//Create during battle copies of player notes
_noteDeck = (Note[])playerStats.CurNotes.Clone(); //Do NOT ever change these notes directly :)
if (_noteDeck.Length <= 0)
{
GD.PushError("Imminent crash: Note Deck is empty!");
GetTree().Paused = true;
}
ShuffleNoteQueue();
ProgressQueue();
MaxValue = playerStats.MaxComboBar;
MaxComboMult = playerStats.MaxComboMult;
_notesToIncreaseCombo = playerStats.NotesToIncreaseCombo;
}
#endregion
#region NoteQueue
[Export]
private Sprite2D _currentNote; //Sprite for current note
private Note _currentNoteInstance; //First note in queue, store outside of queue to maintain first and second
[Export]
private Sprite2D _nextNote; //Secondary note, stored as the first in teh queue
private Queue<Note> _noteQueue = new Queue<Note>();
// Fisher-Yates shuffle from: https://stackoverflow.com/a/1262619
private void ShuffleNoteQueue()
{
List<Note> tempList = new List<Note>(_noteDeck);
int n = tempList.Count;
while (n > 1)
{
n--;
int k = StageProducer.GlobalRng.RandiRange(0, n);
(tempList[k], tempList[n]) = (tempList[n], tempList[k]);
}
_noteQueue = new Queue<Note>(tempList);
}
//Progress the queue by one, and handle shuffling and setting current instances
private void ProgressQueue()
{
if (_noteQueue.Count == 0)
{
ShuffleNoteQueue();
}
if (_currentNoteInstance == null)
{
_currentNoteInstance = _noteQueue.Dequeue();
if (_noteQueue.Count == 0)
{
ShuffleNoteQueue();
}
}
UpdateNoteQueue();
}
private void UpdateNoteQueue()
{
_currentNote.Texture = _currentNoteInstance.Texture;
_nextNote.Texture = _noteQueue.Count > 0 ? _noteQueue.Peek().Texture : null;
}
private Note GetNote(bool getNextNote = false)
{
Note result;
Sprite2D selectedNote;
if (!getNextNote)
{
selectedNote = _currentNote;
result = _currentNoteInstance;
_currentNoteInstance = null;
}
else
{
selectedNote = _nextNote;
result = _noteQueue.Dequeue();
}
NoteQueueParticlesFactory.NoteParticles(selectedNote, selectedNote.Texture);
ProgressQueue();
return result;
}
#endregion
#region Helpers
private Color[] _fillColors = [Colors.Green, Colors.Aqua, Colors.Pink, Colors.Red];
private void FillWithColor(ArrowType type, Color overrideCol = default)
{
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (CurrentBarValue == MaxValue)
return;
Color color = overrideCol == default ? _fillColors[(int)type] : overrideCol;
if (_gradTex.GetPointCount() == 1)
_gradTex.SetColor(0, color);
float offset = (float)((CurrentBarValue) / MaxValue);
_gradTex.AddPoint(offset, color);
}
private void ClearColors()
{
for (int i = _gradTex.GetPointCount() - 1; i > 0; i--)
_gradTex.RemovePoint(i);
}
#endregion
#region Public Functions
public int GetCurrentCombo()
{
return _currentCombo;
}
public double GetCurrentBarValue()
{
return CurrentBarValue;
}
public void ResetCurrentCombo()
{
_currentCombo = 0;
_bonusMult = 0;
}
//For external events to directly change mult
public void IncreaseBonusMult(int amount = 1)
{
_bonusMult += amount;
UpdateComboMultText();
}
public void IncreaseCharge(int amount = 1)
{
FillWithColor(default, Colors.DarkViolet);
CurrentBarValue += amount;
}
public bool CanPlaceNote()
{
return CurrentBarValue >= MaxValue;
}
// Placing a note resets the note placement bar, should only be called if CanPlaceNote was already checked true
public Note NotePlaced()
{
if (!CanPlaceNote())
GD.PushWarning("Note is attempting placement without a full bar!");
string inputType = SaveSystem
.GetConfigValue(SaveSystem.ConfigSettings.InputType)
.ToString();
Note placedNote = GetNote(Input.IsActionPressed(inputType + "_secondaryPlacement"));
CurrentBarValue -= placedNote.CostModifier * MaxValue;
ClearColors();
return placedNote;
}
public void HandleTiming(Timing timed, ArrowType type)
{
if (BattleDirector.PlayerDisabled)
return;
if (timed == Timing.Miss)
{
MissNote();
}
else
{
HitNote(type);
}
}
// Hitting a note increases combo, combo mult, and note placement bar
private void HitNote(ArrowType type)
{
_currentCombo++;
FillWithColor(type);
CurrentBarValue += ComboMult;
UpdateComboMultText();
}
public bool IgnoreMiss; //a one time safe miss
// Missing a note resets combo
private void MissNote()
{
if (IgnoreMiss)
{
IgnoreMiss = false;
return;
}
ResetCurrentCombo();
UpdateComboMultText();
}
public void SetIgnoreMiss(bool ignore)
{
IgnoreMiss = ignore;
}
#endregion
#region Shake
//Juice - https://www.youtube.com/watch?v=LGt-jjVf-ZU
private int _limiter;
private Vector2 _barInitPosition;
private float _baseShake = 1f;
private float _shakeFade = 10f;
private RandomNumberGenerator _rng = new();
private float _shakeStrength;
private void ProcessShake(double delta)
{
_limiter = (_limiter + 1) % 3;
if (_limiter != 1)
return;
if (CurrentBarValue >= MaxValue)
{
_shakeStrength = _baseShake;
}
if (_shakeStrength > 0)
{
_shakeStrength = (float)Mathf.Lerp(_shakeStrength, 0, _shakeFade * delta);
}
_notePlacementBar.Position =
_barInitPosition
+ new Vector2(
_rng.RandfRange(-_shakeStrength, _shakeStrength),
_rng.RandfRange(-_shakeStrength, _shakeStrength)
);
}
#endregion
}