Add instrument selection screen.
This commit is contained in:
parent
a71bb2830a
commit
d435980ac6
@ -1,4 +1,5 @@
|
|||||||
#include "samples/ghhb_game.h"
|
#include "samples/ghhb_game.h"
|
||||||
|
#include "samples/instrument_select.h"
|
||||||
#include "samples/title_screen.h"
|
#include "samples/title_screen.h"
|
||||||
#include "entities/song.h"
|
#include "entities/song.h"
|
||||||
|
|
||||||
@ -7,6 +8,8 @@
|
|||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int INSTRUMENT_GAMEPAD_INDEX[MAX_INSTRUMENT_TYPES] = {-1, -1, -1, -1};
|
||||||
|
|
||||||
Game game;
|
Game game;
|
||||||
|
|
||||||
void update()
|
void update()
|
||||||
@ -30,6 +33,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<InstrumentSelectScreen>("instrument_select");
|
||||||
game.add_scene<GHHBScene>("ghhb");
|
game.add_scene<GHHBScene>("ghhb");
|
||||||
|
|
||||||
Song& song = song_manager->load_song("mary_had_a_lil_lamb", "assets/songs/json/mary.json");
|
Song& song = song_manager->load_song("mary_had_a_lil_lamb", "assets/songs/json/mary.json");
|
||||||
|
|||||||
@ -158,6 +158,8 @@ std::vector<Glyph> load_chart(const char* path)
|
|||||||
const char* const GHHB_CHART_PATH = "assets/songs/json/mary.json";
|
const char* const GHHB_CHART_PATH = "assets/songs/json/mary.json";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
extern int INSTRUMENT_GAMEPAD_INDEX[MAX_INSTRUMENT_TYPES];
|
||||||
|
|
||||||
class GHHBScene : public Scene
|
class GHHBScene : public Scene
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
193
src/samples/instrument_select.h
Normal file
193
src/samples/instrument_select.h
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "engine/prefabs/includes.h"
|
||||||
|
#include "ghhb_game.h"
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class InstrumentSelectScreen : public Scene
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Font font = {0};
|
||||||
|
|
||||||
|
static constexpr int SLOT_TOP = 0;
|
||||||
|
static constexpr int SLOT_BOTTOM = 1;
|
||||||
|
static constexpr int SLOT_LEFT = 2;
|
||||||
|
static constexpr int SLOT_RIGHT = 3;
|
||||||
|
|
||||||
|
static constexpr int BUTTON_SLOT[4] = {
|
||||||
|
SLOT_TOP, // GAMEPAD_BUTTON_LEFT_FACE_UP
|
||||||
|
SLOT_BOTTOM, // GAMEPAD_BUTTON_LEFT_FACE_DOWN
|
||||||
|
SLOT_LEFT, // GAMEPAD_BUTTON_LEFT_FACE_LEFT
|
||||||
|
SLOT_RIGHT, // GAMEPAD_BUTTON_LEFT_FACE_RIGHT
|
||||||
|
};
|
||||||
|
static constexpr int FACE_BUTTONS[4] = {
|
||||||
|
GAMEPAD_BUTTON_LEFT_FACE_UP,
|
||||||
|
GAMEPAD_BUTTON_LEFT_FACE_DOWN,
|
||||||
|
GAMEPAD_BUTTON_LEFT_FACE_LEFT,
|
||||||
|
GAMEPAD_BUTTON_LEFT_FACE_RIGHT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Color BORDER_COLOR;
|
||||||
|
static const Color SECTION_BG_COLOR;
|
||||||
|
|
||||||
|
static constexpr const char* INSTRUMENT_IMAGE_PATHS[MAX_INSTRUMENT_TYPES] = {
|
||||||
|
"assets/instrument_0.png",
|
||||||
|
"assets/instrument_1.png",
|
||||||
|
"assets/instrument_2.png",
|
||||||
|
"assets/instrument_3.png",
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<int, MAX_INSTRUMENT_TYPES> instrument_owner = {-1, -1, -1, -1};
|
||||||
|
std::vector<int> participant_order;
|
||||||
|
|
||||||
|
void init_services() override { add_service<TextureService>(); }
|
||||||
|
|
||||||
|
void init() override
|
||||||
|
{
|
||||||
|
auto font_manager = game->get_manager<FontManager>();
|
||||||
|
font = font_manager->get_font("Roboto");
|
||||||
|
instrument_owner.fill(-1);
|
||||||
|
participant_order.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_or_assign_gamepad_index(int physical_gamepad_id)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < participant_order.size(); i++)
|
||||||
|
{
|
||||||
|
if (participant_order[i] == physical_gamepad_id)
|
||||||
|
return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
if (participant_order.size() < static_cast<size_t>(MAX_INSTRUMENT_TYPES))
|
||||||
|
{
|
||||||
|
participant_order.push_back(physical_gamepad_id);
|
||||||
|
return static_cast<int>(participant_order.size() - 1);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(float delta_time) override
|
||||||
|
{
|
||||||
|
for (int gp = 0; gp < MAX_GAMEPADS; gp++)
|
||||||
|
{
|
||||||
|
if (!IsGamepadAvailable(gp))
|
||||||
|
continue;
|
||||||
|
for (int b = 0; b < 4; b++)
|
||||||
|
{
|
||||||
|
if (IsGamepadButtonPressed(gp, FACE_BUTTONS[b]))
|
||||||
|
{
|
||||||
|
int slot = BUTTON_SLOT[b];
|
||||||
|
int gi = get_or_assign_gamepad_index(gp);
|
||||||
|
if (gi >= 0)
|
||||||
|
instrument_owner[slot] = gi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_selected = true;
|
||||||
|
for (int s = 0; s < MAX_INSTRUMENT_TYPES; s++)
|
||||||
|
{
|
||||||
|
if (instrument_owner[s] < 0)
|
||||||
|
{
|
||||||
|
all_selected = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_selected)
|
||||||
|
{
|
||||||
|
if (IsKeyPressed(KEY_ENTER))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_INSTRUMENT_TYPES; i++)
|
||||||
|
INSTRUMENT_GAMEPAD_INDEX[i] = instrument_owner[i];
|
||||||
|
game->go_to_scene("ghhb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int gp = 0; gp < MAX_GAMEPADS; gp++)
|
||||||
|
{
|
||||||
|
if (IsGamepadAvailable(gp) && IsGamepadButtonPressed(gp, GAMEPAD_BUTTON_MIDDLE_RIGHT))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_INSTRUMENT_TYPES; i++)
|
||||||
|
INSTRUMENT_GAMEPAD_INDEX[i] = instrument_owner[i];
|
||||||
|
game->go_to_scene("ghhb");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw() override
|
||||||
|
{
|
||||||
|
float w = static_cast<float>(GetScreenWidth());
|
||||||
|
float h = static_cast<float>(GetScreenHeight());
|
||||||
|
float cx = w * 0.5f;
|
||||||
|
float cy = h * 0.5f;
|
||||||
|
|
||||||
|
/* Vertices in counter-clockwise order so Raylib fills the triangle. */
|
||||||
|
Vector2 top_tri[3] = {{cx, cy}, {w, 0}, {0, 0}};
|
||||||
|
Vector2 bottom_tri[3] = {{0, h}, {w, h}, {cx, cy}};
|
||||||
|
Vector2 left_tri[3] = {{0, 0}, {0, h}, {cx, cy}};
|
||||||
|
Vector2 right_tri[3] = {{cx, cy}, {w, h}, {w, 0}};
|
||||||
|
|
||||||
|
auto draw_wedge = [this](const Vector2* v, int slot) {
|
||||||
|
Color fill = (instrument_owner[slot] >= 0) ? INSTRUMENT_COLORS[instrument_owner[slot]]
|
||||||
|
: SECTION_BG_COLOR;
|
||||||
|
DrawTriangle(v[0], v[1], v[2], fill);
|
||||||
|
};
|
||||||
|
|
||||||
|
draw_wedge(top_tri, SLOT_TOP);
|
||||||
|
draw_wedge(bottom_tri, SLOT_BOTTOM);
|
||||||
|
draw_wedge(left_tri, SLOT_LEFT);
|
||||||
|
draw_wedge(right_tri, SLOT_RIGHT);
|
||||||
|
|
||||||
|
DrawLineEx(Vector2{0, 0}, Vector2{w, h}, 3.0f, BORDER_COLOR);
|
||||||
|
DrawLineEx(Vector2{w, 0}, Vector2{0, h}, 3.0f, BORDER_COLOR);
|
||||||
|
|
||||||
|
auto* tex_svc = get_service<TextureService>();
|
||||||
|
auto draw_center_icon = [this, tex_svc](float ix, float iy, int slot) {
|
||||||
|
const char* path = INSTRUMENT_IMAGE_PATHS[slot];
|
||||||
|
if (FileExists(path))
|
||||||
|
{
|
||||||
|
Texture2D& tex = tex_svc->get_texture(path);
|
||||||
|
float tw = static_cast<float>(tex.width);
|
||||||
|
float th = static_cast<float>(tex.height);
|
||||||
|
float scale = 1.0f;
|
||||||
|
float max_dim = 120.0f;
|
||||||
|
if (tw > max_dim || th > max_dim)
|
||||||
|
scale = max_dim / (tw > th ? tw : th);
|
||||||
|
float dw = tw * scale;
|
||||||
|
float dh = th * scale;
|
||||||
|
DrawTextureEx(tex, Vector2{ix - dw * 0.5f, iy - dh * 0.5f}, 0.0f, scale, WHITE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawRectangle(static_cast<int>(ix - 40), static_cast<int>(iy - 40), 80, 80,
|
||||||
|
Color{80, 80, 100, 255});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
draw_center_icon(cx, h / 6.0f, SLOT_TOP);
|
||||||
|
draw_center_icon(cx, h * 5.0f / 6.0f, SLOT_BOTTOM);
|
||||||
|
draw_center_icon(w / 6.0f, cy, SLOT_LEFT);
|
||||||
|
draw_center_icon(w * 5.0f / 6.0f, cy, SLOT_RIGHT);
|
||||||
|
|
||||||
|
bool all_selected = true;
|
||||||
|
for (int s = 0; s < MAX_INSTRUMENT_TYPES; s++)
|
||||||
|
{
|
||||||
|
if (instrument_owner[s] < 0)
|
||||||
|
{
|
||||||
|
all_selected = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (all_selected)
|
||||||
|
{
|
||||||
|
const char* prompt = "Press Start to begin";
|
||||||
|
float font_size = 24.0f;
|
||||||
|
float pw = MeasureTextEx(font, prompt, font_size, 1.0f).x;
|
||||||
|
DrawTextEx(font, prompt, Vector2{cx - pw * 0.5f, h - 40.0f}, font_size, 1.0f, WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const Color InstrumentSelectScreen::BORDER_COLOR = {45, 55, 72, 255};
|
||||||
|
inline const Color InstrumentSelectScreen::SECTION_BG_COLOR = {95, 115, 140, 255};
|
||||||
@ -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("ghhb");
|
game->go_to_scene("instrument_select");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user