11#include < cmath>
2+ #include < algorithm>
23#include < filesystem>
34#include < iostream>
45#include < string>
@@ -31,8 +32,35 @@ void set_level(usize i, bool reset_dialog = false);
3132static void DrawTextBoxed (Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint);
3233static void DrawTextBoxedSelectable (Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint, int selectStart, int selectLength, Color selectTint, Color selectBackTint);
3334
35+ void low_pass_filter_cb (void *buffer, unsigned int frames) {
36+ if (!g_gs.current_dialog ) return ;
37+ float *samples = (float *)buffer;
38+ static float prevSampleLeft = 0 .0f ;
39+ static float prevSampleRight = 0 .0f ;
40+ float alpha = 0 .05f ;
41+
42+ for (unsigned int i = 0 ; i < frames * 2 ; i += 2 ) {
43+ samples[i] = prevSampleLeft + alpha * (samples[i] - prevSampleLeft);
44+ prevSampleLeft = samples[i];
45+ samples[i + 1 ] = prevSampleRight + alpha * (samples[i + 1 ] - prevSampleRight);
46+ prevSampleRight = samples[i + 1 ];
47+ }
48+ }
49+
50+ float angle_from_center (const Vector2& center, const Vector2& point) {
51+ return atan2 (point.y - center.y , point.x - center.x );
52+ }
53+
54+ usize number_of_files_in_directory (std::filesystem::path path)
55+ {
56+ using std::filesystem::directory_iterator;
57+ return std::distance (directory_iterator (path), directory_iterator{});
58+ }
59+
3460int main (void )
3561{
62+ SetRandomSeed (time (nullptr ));
63+
3664 for (usize i = 0 ; i < 800 ; i++) {
3765 g_gs.menu_particles .push_back ({
3866 static_cast <float >(GetRandomValue (0 , INITIAL_SCREEN_WIDTH)),
@@ -48,11 +76,26 @@ int main(void)
4876 ChangeDirectory (parentPath.string ().c_str ());
4977 }
5078
51- SetRandomSeed (time (nullptr ));
52-
5379 g_gs.palette = ColorPalette::generate ();
54- for (int i = 0 ; i < 1 ; i++) {
55- g_gs.levels .push_back (Level::read_from_file (TextFormat (RESOURCES_PATH " Level%d.json" , i)));
80+ auto const dir_files
81+ = number_of_files_in_directory (RESOURCES_PATH " levels" );
82+ for (int i = 0 ; i < dir_files; i++) {
83+ g_gs.levels .push_back (Level::read_from_file (TextFormat (RESOURCES_PATH " levels/Level%d.json" , i)));
84+
85+ for (auto & zone : g_gs.levels [i].zones ) {
86+ Vector2 center = { 0 , 0 };
87+ for (const auto & point : zone.points ) {
88+ center.x += point.x ;
89+ center.y += point.y ;
90+ }
91+ center.x /= zone.points .size ();
92+ center.y /= zone.points .size ();
93+
94+ std::sort (zone.points .begin (), zone.points .end (),
95+ [¢er](const Vector2& a, const Vector2& b) {
96+ return angle_from_center (center, a) > angle_from_center (center, b);
97+ });
98+ }
5699 }
57100 } catch (std::exception &e) {
58101 std::cout << e.what () << std::endl;
@@ -67,6 +110,17 @@ int main(void)
67110 SetConfigFlags (FLAG_WINDOW_RESIZABLE | FLAG_MSAA_4X_HINT);
68111#endif
69112 InitWindow (INITIAL_SCREEN_WIDTH, INITIAL_SCREEN_HEIGHT, " ByteRacer" );
113+ InitAudioDevice ();
114+
115+ constexpr auto SONGS = 3 ;
116+ for (usize i = 0 ; i < SONGS; i++) {
117+ auto song = LoadMusicStream (TextFormat (RESOURCES_PATH " music_%d.mp3" , i));
118+ AttachAudioStreamProcessor (song.stream , low_pass_filter_cb);
119+ g_gs.music .push_back (song);
120+ }
121+ g_gs.current_song = GetRandomValue (0 , SONGS-1 );
122+ g_gs.explosion = LoadSound (RESOURCES_PATH " explosion.mp3" );
123+ PlayMusicStream (g_gs.music [g_gs.current_song ]);
70124
71125 g_gs.spritesheet = LoadTexture (" resources/spritesheet.png" );
72126 g_gs.read_dialogs_from_file (" resources/Dialog.json" );
@@ -118,6 +172,15 @@ void set_level(usize i, bool reset_dialog)
118172
119173void produce_frame (void )
120174{
175+ // if (!IsMusicStreamPlaying(g_gs.music[g_gs.current_song])) {
176+ // StopMusicStream(g_gs.music[g_gs.current_song]);
177+ // g_gs.current_song++;
178+ // g_gs.current_song %= g_gs.music.size();
179+ // SeekMusicStream(g_gs.music[g_gs.current_song], 0);
180+ // PlayMusicStream(g_gs.music[g_gs.current_song]);
181+ // }
182+ UpdateMusicStream (g_gs.music [g_gs.current_song ]);
183+
121184 double dt = GetFrameTime ();
122185
123186 if (IsKeyPressed (KEY_R)) {
@@ -160,13 +223,13 @@ void produce_frame(void)
160223 } else if (zone.kind == Level::Zone::Kind::End) {
161224 if (!g_gs.completion_time ) {
162225 g_gs.completion_time = g_gs.time_spent ;
163- g_gs.collected_files = 0 ;
164- g_gs.total_files = 0 ;
226+ g_gs.level ()-> collected_files = 0 ;
227+ g_gs.level ()-> total_files = 0 ;
165228 for (auto &pickup : g_gs.level ()->pickups ) {
166229 if (pickup.kind != Level::Pickup::Kind::File)
167230 continue ;
168- g_gs.total_files ++;
169- g_gs.collected_files += pickup.time_since_pickup != -1 ;
231+ g_gs.level ()-> total_files ++;
232+ g_gs.level ()-> collected_files += pickup.time_since_pickup != -1 ;
170233 }
171234 }
172235 } else if (zone.kind == Level::Zone::Kind::DialogTrigger) {
@@ -191,8 +254,10 @@ void produce_frame(void)
191254
192255 if (g_gs.player .health > PLAYER_MAX_HP)
193256 g_gs.player .health = PLAYER_MAX_HP;
194- else if (g_gs.player .health < 0 )
257+ else if (g_gs.player .health < 0 ) {
195258 set_level (*g_gs.current_level , false );
259+ PlaySound (g_gs.explosion );
260+ }
196261
197262 g_gs.camera .offset .x = g_gs.widthf / 2 .;
198263 g_gs.camera .offset .y = g_gs.heightf / 2 .;
@@ -211,8 +276,10 @@ void produce_frame(void)
211276 continue ;
212277
213278 if (!level.did_initial_dialog ) {
214- g_gs.show_dialog (level.name , 0 );
215- level.did_initial_dialog = true ;
279+ if (level.on_unlock_dialog != -1 ) {
280+ g_gs.show_dialog (level.name , level.on_unlock_dialog );
281+ level.did_initial_dialog = true ;
282+ }
216283 }
217284 }
218285 }
@@ -250,6 +317,11 @@ void produce_frame(void)
250317 float t = 0 ;
251318 int i = 1 ;
252319
320+ g_gs.total_collected_files = 0 ;
321+ for (auto const &level : g_gs.levels ) {
322+ g_gs.total_collected_files += level.collected_files ;
323+ }
324+
253325 constexpr auto HEIGHT = 60 ;
254326 constexpr auto BUTTON_SIZE = 50 ;
255327 constexpr auto PADDING = 20 ;
@@ -271,7 +343,7 @@ void produce_frame(void)
271343 Vector2 prev;
272344 for (auto const &level : g_gs.levels ) {
273345 auto offy = std::sin (t) * HEIGHT;
274- auto x = PADDING + g_gs.menu_scroll + i * BUTTON_SIZE * 3 ;
346+ auto x = PADDING + g_gs.menu_scroll + i * BUTTON_SIZE * 5 ;
275347 auto y = g_gs.heightf / 2 + offy;
276348 Vector2 pos { x, y };
277349
@@ -285,9 +357,10 @@ void produce_frame(void)
285357
286358 bool in = CheckCollisionPointCircle (GetMousePosition (), pos, BUTTON_SIZE);
287359
288- if (level.files_required ) {
360+ bool has_files = g_gs.total_collected_files >= level.files_required ;
361+ if (level.files_required && !has_files) {
289362 constexpr auto FILE_ICON_SIZE = 15 ;
290- auto txt = TextFormat (" %d/%d" , 0 , level.files_required );
363+ auto txt = TextFormat (" %d/%d" , g_gs. total_collected_files , level.files_required );
291364 auto sz = MeasureTextEx (g_gs.font , txt, FILE_ICON_SIZE * 2.5 , 2 );
292365 auto file_pos = pos;
293366 file_pos.y -= BUTTON_SIZE + FILE_ICON_SIZE * 2 ;
@@ -298,7 +371,7 @@ void produce_frame(void)
298371 DrawTextEx (g_gs.font , txt, file_pos, FILE_ICON_SIZE * 2.5 , 2 , g_gs.palette .file );
299372 }
300373
301- if (!level.name .empty ()) {
374+ if (!level.name .empty () && has_files ) {
302375 constexpr auto TEXT_SIZE = 10 ;
303376 auto txt = level.name .c_str ();
304377 auto sz = MeasureTextEx (g_gs.font , txt, TEXT_SIZE * 2.5 , 2 );
@@ -310,15 +383,15 @@ void produce_frame(void)
310383
311384 DrawCircleV (pos, BUTTON_SIZE, g_gs.palette .primary );
312385 DrawCircleV (pos, BUTTON_SIZE - BORDER_WIDTH,
313- in ? g_gs.palette .game_background : g_gs.palette .menu_background );
386+ in && has_files ? g_gs.palette .game_background : g_gs.palette .menu_background );
314387
315388 auto txt = TextFormat (" %d" , i);
316389 auto w = MeasureTextEx (g_gs.font , txt, FONT_SIZE, 2 ).x ;
317390
318391 DrawTextEx (g_gs.font , txt, { x - w / 2 , static_cast <float >(y - FONT_SIZE / 2 ) },
319392 FONT_SIZE, 2 , g_gs.palette .primary );
320393
321- if (IsMouseButtonPressed (0 ) && in) {
394+ if (IsMouseButtonPressed (0 ) && in && has_files ) {
322395 set_level (i - 1 , true );
323396 }
324397
@@ -374,6 +447,8 @@ void produce_frame(void)
374447 EndDrawing ();
375448}
376449
450+ // Shamelessly stolen from Raylib examples :^)
451+
377452static void DrawTextBoxed (Font font, const char *text, Rectangle rec, float fontSize, float spacing, bool wordWrap, Color tint)
378453{
379454 DrawTextBoxedSelectable (font, text, rec, fontSize, spacing, wordWrap, tint, 0 , 0 , WHITE, WHITE);
0 commit comments