Merge branch 'master' of mx.cogentleman.com:cogentleman/guitarHeroButBetter

This commit is contained in:
Joseph DiMaria 2026-01-31 00:55:07 -08:00
commit b2ad69fadf
13 changed files with 99 additions and 19 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -47,7 +47,23 @@ const int KEY_KEYS[LANE_COUNT] = {
KEY_V,
};
struct Note
/* Chromatic scale C4B4: one .wav per lane/button (assets/sounds/nes_harp, copied to build output). */
const char* const LANE_NOTE_WAV[LANE_COUNT] = {
"assets/sounds/nes_harp/nes_harp_C4.wav",
"assets/sounds/nes_harp/nes_harp_Cs4.wav",
"assets/sounds/nes_harp/nes_harp_D4.wav",
"assets/sounds/nes_harp/nes_harp_Ds4.wav",
"assets/sounds/nes_harp/nes_harp_E4.wav",
"assets/sounds/nes_harp/nes_harp_F4.wav",
"assets/sounds/nes_harp/nes_harp_Fs4.wav",
"assets/sounds/nes_harp/nes_harp_G4.wav",
"assets/sounds/nes_harp/nes_harp_Gs4.wav",
"assets/sounds/nes_harp/nes_harp_A4.wav",
"assets/sounds/nes_harp/nes_harp_As4.wav",
"assets/sounds/nes_harp/nes_harp_B4.wav",
};
struct Glyph
{
float time = 0.0f;
int lane = 0;
@ -58,22 +74,22 @@ struct Note
}
};
std::vector<Note> default_chart()
std::vector<Glyph> default_chart()
{
std::vector<Note> notes;
std::vector<Glyph> glyphs;
float t = 2.0f;
for (int i = 0; i < 4; i++)
{
for (int lane = 0; lane < LANE_COUNT; lane++)
{
notes.push_back(Note{t, lane});
glyphs.push_back(Glyph{t, lane});
t += 0.4f;
}
t += 0.6f;
}
for (int lane = 0; lane < LANE_COUNT; lane++)
{
notes.push_back(Note{t, lane});
glyphs.push_back(Glyph{t, lane});
t += 0.2f;
}
t += 0.5f;
@ -81,21 +97,25 @@ std::vector<Note> default_chart()
{
for (int lane = 0; lane < LANE_COUNT; lane++)
{
notes.push_back(Note{t + lane * 0.08f, lane});
glyphs.push_back(Glyph{t + lane * 0.08f, lane});
}
t += 0.8f;
}
return notes;
return glyphs;
}
} // namespace
static const char* const GHHB_MUSIC_PATHS[] = {"assets/music/background.ogg", "assets/music/background.mp3"};
class GHHBScene : public Scene
{
public:
Font font = {0};
std::vector<Note> chart = default_chart();
std::vector<Note*> spawned;
std::unordered_set<Note*> completed_notes;
Music music = {0};
bool music_loaded = false;
std::vector<Glyph> chart = default_chart();
std::vector<Glyph*> spawned;
std::unordered_set<Glyph*> completed_notes;
float song_time = 0.0f;
int score = 0;
int combo = 0;
@ -104,6 +124,8 @@ public:
float screen_width = 0.0f;
float screen_height = 0.0f;
int gamepad_id = 0;
Sound note_sounds[LANE_COUNT] = {0};
bool note_sounds_loaded[LANE_COUNT] = {false};
static constexpr float PRESS_FLASH_DURATION = 0.12f;
static constexpr float MISS_FLASH_DURATION = 0.15f;
float press_flash_timer[LANE_COUNT] = {0};
@ -126,6 +148,35 @@ public:
hit_flash_timer[i] = 0.0f;
miss_flash_timer[i] = 0.0f;
}
if (music_loaded)
{
StopMusicStream(music);
PlayMusicStream(music);
}
}
void on_exit() override
{
if (music_loaded)
{
StopMusicStream(music);
}
}
~GHHBScene() override
{
if (music_loaded)
{
StopMusicStream(music);
UnloadMusicStream(music);
}
for (int i = 0; i < LANE_COUNT; i++)
{
if (note_sounds_loaded[i])
{
UnloadSound(note_sounds[i]);
}
}
}
void init() override
@ -136,6 +187,23 @@ public:
screen_height = static_cast<float>(GetScreenHeight());
hit_line_y = screen_height - RECEPTOR_HEIGHT / 2.0f;
lane_width = screen_width / LANE_COUNT;
for (const char* path : GHHB_MUSIC_PATHS)
{
if (FileExists(path))
{
music = LoadMusicStream(path);
music_loaded = true;
break;
}
}
for (int i = 0; i < LANE_COUNT; i++)
{
if (FileExists(LANE_NOTE_WAV[i]))
{
note_sounds[i] = LoadSound(LANE_NOTE_WAV[i]);
note_sounds_loaded[i] = true;
}
}
}
float lane_center_x(int lane) const
@ -143,15 +211,15 @@ public:
return (lane + 0.5f) * lane_width;
}
bool is_note_hittable(const Note& n) const
bool is_note_hittable(const Glyph& n) const
{
float y = n.y_position(song_time, hit_line_y);
return fabsf(y - hit_line_y) <= HIT_WINDOW_PX;
}
void consume_note(Note* n)
void consume_note(Glyph* n)
{
auto it = std::find_if(spawned.begin(), spawned.end(), [n](Note* p) { return p == n; });
auto it = std::find_if(spawned.begin(), spawned.end(), [n](Glyph* p) { return p == n; });
if (it != spawned.end())
{
hit_flash_timer[n->lane] = PRESS_FLASH_DURATION;
@ -173,7 +241,15 @@ public:
return;
}
if (music_loaded)
{
UpdateMusicStream(music);
song_time = GetMusicTimePlayed(music);
}
else
{
song_time += delta_time;
}
float last_note_time = 0.0f;
for (const auto& n : chart)
@ -198,7 +274,7 @@ public:
continue;
}
bool already = std::find_if(spawned.begin(), spawned.end(),
[&n](Note* p) { return p == &n; }) != spawned.end();
[&n](Glyph* p) { return p == &n; }) != spawned.end();
if (!already && song_time >= n.time - lead_seconds)
{
spawned.push_back(&n);
@ -207,7 +283,7 @@ public:
for (auto it = spawned.begin(); it != spawned.end();)
{
Note* n = *it;
Glyph* n = *it;
float y = n->y_position(song_time, hit_line_y);
if (y > hit_line_y)
{
@ -244,14 +320,18 @@ public:
if (pressed)
{
press_flash_timer[lane] = PRESS_FLASH_DURATION;
if (note_sounds_loaded[lane])
{
PlaySound(note_sounds[lane]);
}
}
if (!pressed)
{
continue;
}
Note* best = nullptr;
Glyph* best = nullptr;
float best_dist = 1e9f;
for (Note* n : spawned)
for (Glyph* n : spawned)
{
if (n->lane != lane)
{
@ -334,7 +414,7 @@ public:
}
DrawLineEx(Vector2{0, hit_line_y}, Vector2{screen_width, hit_line_y}, 3.0f, WHITE);
for (Note* n : spawned)
for (Glyph* n : spawned)
{
float y = n->y_position(song_time, hit_line_y);
if (y < -40.0f || y > screen_height + 40.0f)