Merge branch 'master' of mx.cogentleman.com:cogentleman/guitarHeroButBetter
This commit is contained in:
commit
19ee890687
@ -2,7 +2,8 @@
|
|||||||
"header": {
|
"header": {
|
||||||
"keySignatures": [],
|
"keySignatures": [],
|
||||||
"meta": [],
|
"meta": [],
|
||||||
"name": "",
|
"name": "Mary Had A Little Lamb",
|
||||||
|
"artist": "Mrs Mary",
|
||||||
"ppq": 480,
|
"ppq": 480,
|
||||||
"tempos": [
|
"tempos": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -28,6 +28,7 @@ struct Track {
|
|||||||
|
|
||||||
struct Header {
|
struct Header {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
std::string artist;
|
||||||
int ppq;
|
int ppq;
|
||||||
float bpm;
|
float bpm;
|
||||||
};
|
};
|
||||||
@ -45,7 +46,8 @@ Song parseSong(const rapidjson::Document& doc) {
|
|||||||
if (doc.HasMember("header") && doc["header"].IsObject()) {
|
if (doc.HasMember("header") && doc["header"].IsObject()) {
|
||||||
const auto& h = doc["header"].GetObject();
|
const auto& h = doc["header"].GetObject();
|
||||||
Header header;
|
Header header;
|
||||||
header.name = h["name"].GetString();
|
header.name = h.HasMember("name") && h["name"].IsString() ? h["name"].GetString() : "";
|
||||||
|
header.artist = h.HasMember("artist") && h["artist"].IsString() ? h["artist"].GetString() : "";
|
||||||
header.ppq = h["ppq"].GetInt();
|
header.ppq = h["ppq"].GetInt();
|
||||||
printf("header has tempos: %d\n", h.HasMember("tempos"));
|
printf("header has tempos: %d\n", h.HasMember("tempos"));
|
||||||
if (h.HasMember("tempos") && h["tempos"].IsArray()) {
|
if (h.HasMember("tempos") && h["tempos"].IsArray()) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "samples/ghhb_game.h"
|
#include "samples/ghhb_game.h"
|
||||||
#include "samples/instrument_select.h"
|
#include "samples/instrument_select.h"
|
||||||
|
#include "samples/song_select.h"
|
||||||
#include "samples/title_screen.h"
|
#include "samples/title_screen.h"
|
||||||
#include "entities/song.h"
|
#include "entities/song.h"
|
||||||
|
|
||||||
@ -10,6 +11,7 @@
|
|||||||
|
|
||||||
int INSTRUMENT_GAMEPAD_INDEX[MAX_INSTRUMENT_TYPES] = {-1, -1, -1, -1};
|
int INSTRUMENT_GAMEPAD_INDEX[MAX_INSTRUMENT_TYPES] = {-1, -1, -1, -1};
|
||||||
int INSTRUMENT_PHYSICAL_GAMEPAD[MAX_INSTRUMENT_TYPES] = {-1, -1, -1, -1};
|
int INSTRUMENT_PHYSICAL_GAMEPAD[MAX_INSTRUMENT_TYPES] = {-1, -1, -1, -1};
|
||||||
|
std::string SELECTED_SONG_PATH = "assets/songs/json/mary.json";
|
||||||
|
|
||||||
Game game;
|
Game game;
|
||||||
|
|
||||||
@ -34,6 +36,7 @@ int main(int argc, char** argv)
|
|||||||
font_manager->set_texture_filter("Roboto", TEXTURE_FILTER_BILINEAR);
|
font_manager->set_texture_filter("Roboto", TEXTURE_FILTER_BILINEAR);
|
||||||
|
|
||||||
game.add_scene<TitleScreen>("title");
|
game.add_scene<TitleScreen>("title");
|
||||||
|
game.add_scene<SongSelectScreen>("song_select");
|
||||||
game.add_scene<InstrumentSelectScreen>("instrument_select");
|
game.add_scene<InstrumentSelectScreen>("instrument_select");
|
||||||
game.add_scene<GHHBScene>("ghhb");
|
game.add_scene<GHHBScene>("ghhb");
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "background.h"
|
#include "background.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -184,10 +185,9 @@ std::vector<Glyph> load_chart(const char* path)
|
|||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const char* const GHHB_CHART_PATH = "assets/songs/json/tetris.json";
|
|
||||||
const char* const GHHB_CHART_PATH = "assets/songs/json/mary.json";
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
extern std::string SELECTED_SONG_PATH;
|
||||||
extern int INSTRUMENT_GAMEPAD_INDEX[MAX_INSTRUMENT_TYPES];
|
extern int INSTRUMENT_GAMEPAD_INDEX[MAX_INSTRUMENT_TYPES];
|
||||||
extern int INSTRUMENT_PHYSICAL_GAMEPAD[MAX_INSTRUMENT_TYPES];
|
extern int INSTRUMENT_PHYSICAL_GAMEPAD[MAX_INSTRUMENT_TYPES];
|
||||||
|
|
||||||
@ -222,6 +222,14 @@ public:
|
|||||||
|
|
||||||
void on_enter() override
|
void on_enter() override
|
||||||
{
|
{
|
||||||
|
chart = load_chart(SELECTED_SONG_PATH.c_str());
|
||||||
|
float first_note_time = 0.0f;
|
||||||
|
if (!chart.empty())
|
||||||
|
{
|
||||||
|
first_note_time = chart.front().time;
|
||||||
|
float lead_seconds = (hit_line_y - 60.0f) / SCROLL_PX_PER_SEC;
|
||||||
|
chart_time_offset = lead_seconds + LEAD_OFFSET_SECONDS - first_note_time;
|
||||||
|
}
|
||||||
song_time = 0.0f;
|
song_time = 0.0f;
|
||||||
score = 0;
|
score = 0;
|
||||||
combo = 0;
|
combo = 0;
|
||||||
@ -293,14 +301,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chart = load_chart(GHHB_CHART_PATH);
|
|
||||||
float first_note_time = 0.0f;
|
|
||||||
if (!chart.empty())
|
|
||||||
{
|
|
||||||
first_note_time = chart.front().time;
|
|
||||||
float lead_seconds = (hit_line_y - 60.0f) / SCROLL_PX_PER_SEC;
|
|
||||||
chart_time_offset = lead_seconds + LEAD_OFFSET_SECONDS - first_note_time;
|
|
||||||
}
|
|
||||||
background = add_game_object<Background>();
|
background = add_game_object<Background>();
|
||||||
background->add_tag("background");
|
background->add_tag("background");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,10 +79,15 @@ public:
|
|||||||
int slot = BUTTON_SLOT[b];
|
int slot = BUTTON_SLOT[b];
|
||||||
int gi = get_or_assign_gamepad_index(gp);
|
int gi = get_or_assign_gamepad_index(gp);
|
||||||
if (gi >= 0)
|
if (gi >= 0)
|
||||||
|
{
|
||||||
|
if (instrument_owner[slot] == gi)
|
||||||
|
instrument_owner[slot] = -1;
|
||||||
|
else
|
||||||
instrument_owner[slot] = gi;
|
instrument_owner[slot] = gi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool all_selected = true;
|
bool all_selected = true;
|
||||||
for (int s = 0; s < MAX_INSTRUMENT_TYPES; s++)
|
for (int s = 0; s < MAX_INSTRUMENT_TYPES; s++)
|
||||||
|
|||||||
187
src/samples/song_select.h
Normal file
187
src/samples/song_select.h
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "engine/prefabs/includes.h"
|
||||||
|
#include "entities/song.h"
|
||||||
|
#include "rapidjson/filereadstream.h"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
extern std::string SELECTED_SONG_PATH;
|
||||||
|
|
||||||
|
struct SongEntry
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::string artist;
|
||||||
|
std::string path;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::vector<SongEntry> build_song_list(const std::vector<std::string>& paths)
|
||||||
|
{
|
||||||
|
std::vector<SongEntry> entries;
|
||||||
|
for (const std::string& path : paths)
|
||||||
|
{
|
||||||
|
std::FILE* fp = std::fopen(path.c_str(), "rb");
|
||||||
|
if (!fp)
|
||||||
|
continue;
|
||||||
|
char read_buf[65536];
|
||||||
|
rapidjson::FileReadStream is(fp, read_buf, sizeof(read_buf));
|
||||||
|
rapidjson::Document doc;
|
||||||
|
if (doc.ParseStream(is).HasParseError())
|
||||||
|
{
|
||||||
|
std::fclose(fp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::fclose(fp);
|
||||||
|
Song song = parseSong(doc);
|
||||||
|
entries.push_back(
|
||||||
|
{song.header.name.empty() ? path : song.header.name, song.header.artist, path});
|
||||||
|
}
|
||||||
|
while (entries.size() < 4)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < entries.size() && entries.size() < 4; i++)
|
||||||
|
entries.push_back(entries[i]);
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SongSelectScreen : public Scene
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr int VISIBLE_SLOTS = 4;
|
||||||
|
|
||||||
|
Font font = {0};
|
||||||
|
std::vector<SongEntry> songs;
|
||||||
|
int selected_index = 0;
|
||||||
|
int scroll_offset = 0;
|
||||||
|
|
||||||
|
void init() override
|
||||||
|
{
|
||||||
|
auto font_manager = game->get_manager<FontManager>();
|
||||||
|
font = font_manager->get_font("Roboto");
|
||||||
|
std::vector<std::string> paths = {"assets/songs/json/mary.json"};
|
||||||
|
songs = build_song_list(paths);
|
||||||
|
selected_index = 0;
|
||||||
|
scroll_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(float delta_time) override
|
||||||
|
{
|
||||||
|
bool up = IsKeyPressed(KEY_UP);
|
||||||
|
bool down = IsKeyPressed(KEY_DOWN);
|
||||||
|
for (int gp = 0; gp < 4; gp++)
|
||||||
|
{
|
||||||
|
if (IsGamepadAvailable(gp))
|
||||||
|
{
|
||||||
|
if (IsGamepadButtonPressed(gp, GAMEPAD_BUTTON_LEFT_FACE_UP))
|
||||||
|
up = true;
|
||||||
|
if (IsGamepadButtonPressed(gp, GAMEPAD_BUTTON_LEFT_FACE_DOWN))
|
||||||
|
down = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int n = static_cast<int>(songs.size());
|
||||||
|
if (up)
|
||||||
|
{
|
||||||
|
if (selected_index > 0)
|
||||||
|
selected_index--;
|
||||||
|
else if (scroll_offset > 0)
|
||||||
|
scroll_offset--;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scroll_offset = n > VISIBLE_SLOTS ? n - VISIBLE_SLOTS : 0;
|
||||||
|
selected_index = n > VISIBLE_SLOTS ? VISIBLE_SLOTS - 1 : n - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (down)
|
||||||
|
{
|
||||||
|
if (selected_index < VISIBLE_SLOTS - 1 && scroll_offset + selected_index < n - 1)
|
||||||
|
selected_index++;
|
||||||
|
else if (scroll_offset + VISIBLE_SLOTS < n)
|
||||||
|
scroll_offset++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scroll_offset = 0;
|
||||||
|
selected_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool confirm = IsKeyPressed(KEY_ENTER);
|
||||||
|
for (int gp = 0; gp < 4; gp++)
|
||||||
|
{
|
||||||
|
if (IsGamepadAvailable(gp) && IsGamepadButtonPressed(gp, GAMEPAD_BUTTON_MIDDLE_RIGHT))
|
||||||
|
confirm = true;
|
||||||
|
}
|
||||||
|
if (confirm && !songs.empty())
|
||||||
|
{
|
||||||
|
int idx = scroll_offset + selected_index;
|
||||||
|
if (idx >= 0 && idx < static_cast<int>(songs.size()))
|
||||||
|
{
|
||||||
|
SELECTED_SONG_PATH = songs[idx].path;
|
||||||
|
game->go_to_scene("instrument_select");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() override
|
||||||
|
{
|
||||||
|
float w = static_cast<float>(GetScreenWidth());
|
||||||
|
float h = static_cast<float>(GetScreenHeight());
|
||||||
|
|
||||||
|
ClearBackground(SKYBLUE);
|
||||||
|
|
||||||
|
const char* title_text = "Select Song";
|
||||||
|
float title_size = 48.0f;
|
||||||
|
float title_w = MeasureTextEx(font, title_text, title_size, 1.0f).x;
|
||||||
|
DrawTextEx(font, title_text, Vector2{(w - title_w) * 0.5f, 60.0f}, title_size, 1.0f, WHITE);
|
||||||
|
|
||||||
|
float row_height = 80.0f;
|
||||||
|
float start_y = 180.0f;
|
||||||
|
float list_center_x = w * 0.5f;
|
||||||
|
float name_size = 28.0f;
|
||||||
|
float artist_size = 18.0f;
|
||||||
|
float artist_offset_x = 0.0f;
|
||||||
|
Color highlight_bg = {60, 80, 120, 220};
|
||||||
|
Color highlight_border = {100, 130, 180, 255};
|
||||||
|
float content_height = name_size + 4.0f + artist_size;
|
||||||
|
float box_pad_v = 6.0f;
|
||||||
|
float highlight_height = content_height + box_pad_v * 2.0f;
|
||||||
|
|
||||||
|
for (int i = 0; i < VISIBLE_SLOTS; i++)
|
||||||
|
{
|
||||||
|
int list_idx = scroll_offset + i;
|
||||||
|
float y = start_y + i * row_height;
|
||||||
|
bool selected = (i == selected_index);
|
||||||
|
|
||||||
|
if (list_idx < static_cast<int>(songs.size()))
|
||||||
|
{
|
||||||
|
const SongEntry& e = songs[list_idx];
|
||||||
|
if (selected)
|
||||||
|
{
|
||||||
|
float box_w = w * 0.45f;
|
||||||
|
float box_x = (w - box_w) * 0.5f;
|
||||||
|
float box_y = y - box_pad_v;
|
||||||
|
DrawRectangleRounded(
|
||||||
|
Rectangle{box_x, box_y, box_w, highlight_height}, 0.2f, 12, highlight_bg);
|
||||||
|
DrawRectangleRoundedLines(
|
||||||
|
Rectangle{box_x, box_y, box_w, highlight_height}, 0.2f, 12,
|
||||||
|
highlight_border);
|
||||||
|
}
|
||||||
|
float name_w = MeasureTextEx(font, e.name.c_str(), name_size, 1.0f).x;
|
||||||
|
DrawTextEx(font, e.name.c_str(),
|
||||||
|
Vector2{list_center_x - name_w * 0.5f, y}, name_size, 1.0f, WHITE);
|
||||||
|
if (!e.artist.empty())
|
||||||
|
{
|
||||||
|
float artist_w = MeasureTextEx(font, e.artist.c_str(), artist_size, 1.0f).x;
|
||||||
|
DrawTextEx(font, e.artist.c_str(),
|
||||||
|
Vector2{list_center_x - artist_w * 0.5f + artist_offset_x,
|
||||||
|
y + name_size + 4.0f},
|
||||||
|
artist_size, 1.0f, Color{200, 200, 200, 255});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* hint = "D-Pad Up/Down | Start to confirm";
|
||||||
|
float hint_size = 20.0f;
|
||||||
|
float hint_w = MeasureTextEx(font, hint, hint_size, 1.0f).x;
|
||||||
|
DrawTextEx(font, hint, Vector2{(w - hint_w) * 0.5f, h - 50.0f}, hint_size, 1.0f, WHITE);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -18,7 +18,7 @@ public:
|
|||||||
// Trigger scene change on Enter key or gamepad start button.
|
// Trigger scene change on Enter key or gamepad start button.
|
||||||
if (IsKeyPressed(KEY_ENTER) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_MIDDLE_RIGHT))
|
if (IsKeyPressed(KEY_ENTER) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_MIDDLE_RIGHT))
|
||||||
{
|
{
|
||||||
game->go_to_scene("instrument_select");
|
game->go_to_scene("song_select");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user