1
0
mirror of synced 2024-11-12 01:40:47 +01:00

Save before fixing

This commit is contained in:
Stepland 2019-11-03 00:55:54 +01:00
parent a111820c9d
commit 97d5f1493a
20 changed files with 338 additions and 265 deletions

Binary file not shown.

View File

@ -16,15 +16,23 @@ filesystem = cpp.find_library('stdc++fs')
sources = [
'src/Main.cpp',
'src/Data/Chart.hpp',
'src/Data/KeyMapping.hpp',
'src/Data/KeyMapping.cpp',
'src/Data/Note.hpp',
'src/Data/Note.cpp',
'srx/Data/Score.hpp',
'src/Data/Score.hpp',
'src/Data/SongList.hpp',
'src/Data/SongList.cpp',
'src/Screens/Gameplay.hpp',
# 'src/Screens/Gameplay.hpp',
'src/Screens/MusicSelect/MusicSelect.hpp',
'src/Screens/MusicSelect/MusicSelect.cpp',
'src/Screens/Result.hpp',
'src/Screens/MusicSelect/Panel.hpp',
'src/Screens/MusicSelect/Panel.cpp',
'src/Screens/MusicSelect/Resources.hpp',
'src/Screens/MusicSelect/Resources.cpp',
'src/Screens/MusicSelect/Ribbon.hpp',
'src/Screens/MusicSelect/Ribbon.cpp',
# 'src/Screens/Result.hpp',
'src/Resources/CoverAtlas.hpp',
'src/Resources/CoverAtlas.cpp',
]

View File

@ -1,54 +0,0 @@
#include "KeyMaping.hpp"
PanelCoords toCoord(PanelEnum panel) {
auto num = static_cast<int>(panel);
return {num % 4, num / 4};
}
KeyMaping::KeyMaping() {
m_key_to_panel[sf::Keyboard::Num1] = PanelEnum::P1;
m_key_to_panel[sf::Keyboard::Num2] = PanelEnum::P2;
m_key_to_panel[sf::Keyboard::Num3] = PanelEnum::P3;
m_key_to_panel[sf::Keyboard::Num4] = PanelEnum::P4;
m_key_to_panel[sf::Keyboard::A] = PanelEnum::P5;
m_key_to_panel[sf::Keyboard::Z] = PanelEnum::P6;
m_key_to_panel[sf::Keyboard::E] = PanelEnum::P7;
m_key_to_panel[sf::Keyboard::R] = PanelEnum::P8;
m_key_to_panel[sf::Keyboard::Q] = PanelEnum::P9;
m_key_to_panel[sf::Keyboard::S] = PanelEnum::P10;
m_key_to_panel[sf::Keyboard::D] = PanelEnum::P11;
m_key_to_panel[sf::Keyboard::F] = PanelEnum::P12;
m_key_to_panel[sf::Keyboard::W] = PanelEnum::P13;
m_key_to_panel[sf::Keyboard::X] = PanelEnum::P14;
m_key_to_panel[sf::Keyboard::C] = PanelEnum::P15;
m_key_to_panel[sf::Keyboard::V] = PanelEnum::P16;
for (const auto& [key, panel] : m_key_to_panel) {
m_panel_to_key[panel] = key;
}
}
void KeyMaping::setPanelToKey(const PanelEnum& panel, const sf::Keyboard::Key& key) {
if (m_key_to_panel.find(key) != m_key_to_panel.end()) {
m_panel_to_key.erase(m_key_to_panel[key]);
m_key_to_panel.erase(key);
}
m_panel_to_key[panel] = key;
m_key_to_panel[key] = panel;
}
std::optional<PanelEnum> KeyMaping::key_to_panel(const sf::Keyboard::Key& key) {
try {
return m_key_to_panel.at(key);
} catch(const std::exception& e) {
return {};
}
}
std::optional<sf::Keyboard::Key> KeyMaping::panel_to_key(const PanelEnum& panel) {
try {
return m_panel_to_key.at(panel);
} catch(const std::exception& e) {
return {};
}
}

View File

@ -1,43 +0,0 @@
#pragma once
#include <optional>
#include <unordered_map>
#include <SFML/Window.hpp>
enum class PanelEnum {
P1,
P2,
P3,
P4,
P5,
P6,
P7,
P8,
P9,
P10,
P11,
P12,
P13,
P14,
P15,
P16,
};
struct PanelCoords {
unsigned int x;
unsigned int y;
};
PanelCoords toCoord(PanelEnum panel);
class KeyMaping {
public:
KeyMaping();
void setPanelToKey(const PanelEnum& panel, const sf::Keyboard::Key& key);
std::optional<PanelEnum> key_to_panel(const sf::Keyboard::Key& key);
std::optional<sf::Keyboard::Key> panel_to_key(const PanelEnum& panel);
private:
std::unordered_map<sf::Keyboard::Key, PanelEnum> m_key_to_panel;
std::unordered_map<PanelEnum, sf::Keyboard::Key> m_panel_to_key;
};

54
src/Data/KeyMapping.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "KeyMapping.hpp"
ButtonCoords toCoord(Button panel) {
auto num = static_cast<int>(panel);
return {num % 4, num / 4};
}
KeyMapping::KeyMapping() {
m_key_to_button[sf::Keyboard::Num1] = Button::B1;
m_key_to_button[sf::Keyboard::Num2] = Button::B2;
m_key_to_button[sf::Keyboard::Num3] = Button::B3;
m_key_to_button[sf::Keyboard::Num4] = Button::B4;
m_key_to_button[sf::Keyboard::A] = Button::B5;
m_key_to_button[sf::Keyboard::Z] = Button::B6;
m_key_to_button[sf::Keyboard::E] = Button::B7;
m_key_to_button[sf::Keyboard::R] = Button::B8;
m_key_to_button[sf::Keyboard::Q] = Button::B9;
m_key_to_button[sf::Keyboard::S] = Button::B10;
m_key_to_button[sf::Keyboard::D] = Button::B11;
m_key_to_button[sf::Keyboard::F] = Button::B12;
m_key_to_button[sf::Keyboard::W] = Button::B13;
m_key_to_button[sf::Keyboard::X] = Button::B14;
m_key_to_button[sf::Keyboard::C] = Button::B15;
m_key_to_button[sf::Keyboard::V] = Button::B16;
for (const auto& [key, panel] : m_key_to_button) {
m_button_to_key[panel] = key;
}
}
void KeyMapping::setPanelToKey(const Button& panel, const sf::Keyboard::Key& key) {
if (m_key_to_button.find(key) != m_key_to_button.end()) {
m_button_to_key.erase(m_key_to_button[key]);
m_key_to_button.erase(key);
}
m_button_to_key[panel] = key;
m_key_to_button[key] = panel;
}
std::optional<Button> KeyMapping::key_to_button(const sf::Keyboard::Key& key) {
try {
return m_key_to_button.at(key);
} catch(const std::exception& e) {
return {};
}
}
std::optional<sf::Keyboard::Key> KeyMapping::button_to_key(const Button& panel) {
try {
return m_button_to_key.at(panel);
} catch(const std::exception& e) {
return {};
}
}

43
src/Data/KeyMapping.hpp Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <optional>
#include <unordered_map>
#include <SFML/Window.hpp>
enum class Button {
B1,
B2,
B3,
B4,
B5,
B6,
B7,
B8,
B9,
B10,
B11,
B12,
B13,
B14,
B15,
B16,
};
struct ButtonCoords {
unsigned int x;
unsigned int y;
};
ButtonCoords toCoord(Button button);
class KeyMapping {
public:
KeyMapping();
void setPanelToKey(const Button& button, const sf::Keyboard::Key& key);
std::optional<Button> key_to_button(const sf::Keyboard::Key& key);
std::optional<sf::Keyboard::Key> button_to_key(const Button& button);
private:
std::unordered_map<sf::Keyboard::Key, Button> m_key_to_button;
std::unordered_map<Button, sf::Keyboard::Key> m_button_to_key;
};

View File

@ -16,11 +16,11 @@ Data::Note::Note(
throw std::out_of_range("Tried creating a note with invalid position : "+std::to_string(t_position));
}
if (t_length.asMicroseconds < 0) {
if (t_length.asMicroseconds() < 0) {
throw std::out_of_range("Tried creating a long note with negative length : "+std::to_string(t_length.asSeconds)+ "s");
}
if (t_length.asMicroseconds > 0) {
if (t_length.asMicroseconds() > 0) {
if (t_tail_position > 5) {
throw std::out_of_range("Tried creating a long note with invalid tail position : "+std::to_string(t_tail_position));
}

View File

@ -9,111 +9,115 @@
namespace fs = std::filesystem;
Data::SongList::SongList::SongList() {
namespace Data {
// Loading all song metadata
for (const auto& folder : getSongFolders()) {
try {
songs.emplace_back(folder);
} catch (const std::exception& e) {
std::cerr << "Exception while parsing song folder "
<< folder.string() << " : " << e.what() << '\n';
continue;
}
}
}
SongList::SongList::SongList() {
const std::vector<fs::path> Data::getSongFolders() {
std::vector<fs::path> song_folders;
for (const auto& dir_item : fs::directory_iterator("songs/")) {
if (dir_item.is_directory()) {
for (auto& path : recursiveSongSearch(dir_item.path())) {
song_folders.push_back(path);
// Loading all song metadata
for (const auto& folder : getSongFolders()) {
try {
songs.emplace_back(folder);
} catch (const std::exception& e) {
std::cerr << "Exception while parsing song folder "
<< folder.string() << " : " << e.what() << '\n';
continue;
}
}
}
return song_folders;
}
std::list<fs::path> Data::recursiveSongSearch(fs::path song_or_pack) {
std::list<fs::path> res;
fs::directory_iterator folder{song_or_pack};
if (
std::any_of(
fs::begin(folder),
fs::end(folder),
[](const fs::directory_entry& de) {
de.path().extension() == ".memo" or
de.path().extension() == ".memon";
const std::vector<fs::path> getSongFolders() {
std::vector<fs::path> song_folders;
for (const auto& dir_item : fs::directory_iterator("songs/")) {
if (dir_item.is_directory()) {
for (auto& path : recursiveSongSearch(dir_item.path())) {
song_folders.push_back(path);
}
}
)
) {
res.push_back(song_or_pack);
return res;
} else {
for (auto& p : fs::directory_iterator(song_or_pack)) {
if (p.is_directory()) {
res.splice(res.end(), recursiveSongSearch(p));
}
return song_folders;
}
std::list<fs::path> recursiveSongSearch(fs::path song_or_pack) {
std::list<fs::path> res;
fs::directory_iterator folder{song_or_pack};
if (
std::any_of(
fs::begin(folder),
fs::end(folder),
[](const fs::directory_entry& de) {
de.path().extension() == ".memo" or
de.path().extension() == ".memon";
}
)
) {
res.push_back(song_or_pack);
return res;
} else {
for (auto& p : fs::directory_iterator(song_or_pack)) {
if (p.is_directory()) {
res.splice(res.end(), recursiveSongSearch(p));
}
}
return res;
}
}
Song::Song(fs::path song_folder) {
// .memon ?
auto memon_files = getMemonFiles(song_folder);
if (not memon_files.empty()) {
if (memon_files.size() > 1) {
throw std::invalid_argument("Multiple .memon files");
} else {
stepland::memon m;
std::ifstream file(memon_files.back());
file >> m;
this->title = m.song_title;
this->artist = m.artist;
if (not m.album_cover_path.empty()) {
this->cover.emplace(m.album_cover_path);
}
if (not m.music_path.empty()) {
this->audio.emplace(m.music_path);
}
for (const auto& [difficulty, chart] : m.charts) {
this->chart_levels[difficulty] = chart.level;
}
}
} else {
// .memo ?
auto memo_files = getMemoFiles(song_folder);
if (not memo_files.empty()) {
throw std::exception("jujube does not support .memo files for now ...");
} else {
throw std::invalid_argument("No valid file found in song folder");
}
}
}
const std::vector<fs::path>& getMemoFiles(fs::path song_folder) {
std::vector<fs::path> res;
for (const auto& p : fs::directory_iterator(song_folder)) {
if (p.path().extension() == ".memo") {
res.push_back(p.path());
}
}
return res;
}
}
Data::Song::Song(fs::path song_folder) {
// .memon ?
auto memon_files = getMemonFiles(song_folder);
if (not memon_files.empty()) {
if (memon_files.size() > 1) {
throw std::invalid_argument("Multiple .memon files");
} else {
stepland::memon m;
std::ifstream file(memon_files.back());
file >> m;
this->title = m.song_title;
this->artist = m.artist;
if (not m.album_cover_path.empty()) {
this->cover.emplace(m.album_cover_path);
}
if (not m.music_path.empty()) {
this->audio.emplace(m.music_path);
}
for (const auto& [difficulty, chart] : m.charts) {
this->chart_levels[difficulty] = chart.level;
const std::vector<fs::path>& getMemonFiles(fs::path song_folder) {
std::vector<fs::path> res;
for (const auto& p : fs::directory_iterator(song_folder)) {
if (p.path().extension() == ".memon") {
res.push_back(p.path());
}
}
} else {
// .memo ?
auto memo_files = getMemoFiles(song_folder);
if (not memo_files.empty()) {
throw std::exception("jujube does not support .memo files for now ...");
} else {
throw std::invalid_argument("No valid file found in song folder");
}
return res;
}
}
const std::vector<fs::path>& Data::getMemoFiles(fs::path song_folder) {
std::vector<fs::path> res;
for (const auto& p : fs::directory_iterator(song_folder)) {
if (p.path().extension() == ".memo") {
res.push_back(p.path());
}
}
return res;
}
const std::vector<fs::path>& Data::getMemonFiles(fs::path song_folder) {
std::vector<fs::path> res;
for (const auto& p : fs::directory_iterator(song_folder)) {
if (p.path().extension() == ".memon") {
res.push_back(p.path());
}
}
return res;
}
}

View File

@ -2,6 +2,7 @@
#include <filesystem>
#include <iterator>
#include <list>
#include <optional>
#include <string>
#include <unordered_map>

View File

@ -1,19 +1,23 @@
#include <SFML/Graphics.hpp>
#include "Data/Chart.hpp"
#include "Data/Score.hpp"
#include "Data/SongList.hpp"
// #include "Data/Chart.hpp"
// #include "Data/Score.hpp"
#include "Screens/MusicSelect/MusicSelect.hpp"
#include "Screens/Gameplay.hpp"
#include "Screens/Result.hpp"
// #include "Screens/Gameplay.hpp"
// #include "Screens/Result.hpp"
int main(int argc, char const *argv[]) {
sf::RenderWindow window(sf::VideoMode(800,600), "jujube");
window.setVerticalSyncEnabled(true);
MusicSelect::Screen music_select;
Data::SongList song_list;
MusicSelect::Screen music_select{song_list};
music_select.select_chart(window);
/*
while (true) {
Chart& selected_chart = music_select.select_chart(window);
@ -25,6 +29,7 @@ int main(int argc, char const *argv[]) {
result_screen.display(window);
}
*/
return 0;

View File

@ -2,12 +2,11 @@
#include <iostream>
#include "../../Data/KeyMaping.hpp"
#include "../../Data/KeyMapping.hpp"
MusicSelect::Screen::Screen(const Data::SongList& t_song_list) :
song_list(t_song_list),
resources(),
state(t_song_list)
ribbon(MusicSelect::Ribbon::test_sort())
{
for (const auto& song : song_list.songs) {
if (song.cover) {
@ -20,7 +19,9 @@ MusicSelect::Screen::Screen(const Data::SongList& t_song_list) :
}
}
Chart& MusicSelect::Screen::select_chart(sf::Window& window) {
void MusicSelect::Screen::select_chart(sf::RenderWindow& window) {
window.create(sf::VideoMode(600,600), "jujube", sf::Style::None);
bool chart_selected = false;
while (not chart_selected) {
sf::Event event;
@ -33,21 +34,23 @@ Chart& MusicSelect::Screen::select_chart(sf::Window& window) {
break;
}
}
// drawing the ribbon
for (size_t panel = 0; panel < 12; panel++) {
ribbon.at(panel)->draw(
*this,
window,
sf::FloatRect((panel%4)*150.f, (panel/4)*150.f, 150.f, 150.f)
);
}
window.display();
}
}
void MusicSelect::Screen::handle_key(const sf::Event::KeyEvent& key_event) {
auto panel = key_mapping.key_to_panel(key_event.code);
auto panel = key_mapping.key_to_button(key_event.code);
if (panel) {
if (PanelEnum::P2 <= *panel and *panel <= PanelEnum::P12) {
auto coord = toCoord(*panel);
auto ribbon_size = state.ribbon.get_layout().size();
state
.ribbon
.get_layout()
.at((state.ribbon_position + coord.x) % ribbon_size)
.at(coord.y)
->click(state);
if (Button::B2 <= *panel and *panel <= Button::B12) {
ribbon.at()
}
}
}

View File

@ -6,8 +6,8 @@
#include "../../Data/SongList.hpp"
#include "../../Data/Chart.hpp"
#include "../../Data/KeyMaping.hpp"
#include "State.hpp"
#include "../../Data/KeyMapping.hpp"
#include "Ribbon.hpp"
#include "Resources.hpp"
namespace MusicSelect {
@ -17,12 +17,20 @@ namespace MusicSelect {
class Screen {
public:
Screen(const Data::SongList& t_song_list);
Chart& select_chart(sf::Window& window);
void select_chart(sf::RenderWindow& window);
private:
// Data
const Data::SongList& song_list;
// Resources
Resources resources;
State state;
KeyMaping key_mapping;
// State
Ribbon ribbon;
std::optional<std::reference_wrapper<SongPanel>> selected_panel;
KeyMapping key_mapping;
void handle_key(const sf::Event::KeyEvent& key_event);
};
};

View File

@ -1,6 +1,38 @@
#include "Panel.hpp"
#include <SFML/Graphics.hpp>
void MusicSelect::CategoryPanel::display(State& state, sf::Window& window, sf::FloatRect area) {
#include "MusicSelect.hpp"
void MusicSelect::CategoryPanel::draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) {
sf::RectangleShape frame{{area.width*0.9f, area.height*0.9f}};
frame.setFillColor(sf::Color::Black);
frame.setOutlineThickness(1.f);
frame.setOutlineColor(sf::Color::White);
frame.setOrigin(frame.getSize().x / 2.f, frame.getSize().y / 2.f);
frame.setPosition(area.left+area.width/2.f, area.top+area.height/2.f);
target.draw(frame);
sf::Text top_text;
top_text.setFont(resources.noto_sans_medium);
top_text.setString("category");
top_text.setCharacterSize(12U);
top_text.setFillColor(sf::Color::White);
auto bounds = top_text.getLocalBounds();
top_text.setScale(area.width*0.45f / bounds.width, area.width*0.45f / bounds.width);
top_text.setPosition(area.left + area.width*0.15f, area.top + area.height*0.15f);
sf::Text label_text;
label_text.setFont(resources.noto_sans_medium);
label_text.setString(this->label);
label_text.setCharacterSize(24U);
label_text.setFillColor(sf::Color::White);
auto bounds = label_text.getLocalBounds();
label_text.setOrigin(bounds.width / 2.f, bounds.height / 2.f);
if (bounds.height > bounds.width) {
label_text.setScale(area.height*0.8f / bounds.height, area.height*0.8f / bounds.height);
} else {
label_text.setScale(area.width*0.8f / bounds.width, area.width*0.8f / bounds.width);
}
label_text.setPosition(area.left + area.width / 2.f, area.top + area.height / 2.f);
}

View File

@ -2,31 +2,35 @@
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include "State.hpp"
#include "Resources.hpp"
namespace MusicSelect {
// A Panel holds anything that can go under a panel on the moving part
class Screen;
// A Panel holds anything that can go under a button on the moving part
// of the music select screen, be it nothing, a sort indicator, or a song
class Panel {
public:
// What happens when you click on the panel
virtual void click(State& state) = 0;
virtual void click(Screen& screen) = 0;
// How the panel should be displayed
virtual void display(State& state, sf::Window& window, sf::FloatRect area) = 0;
virtual void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) = 0;
virtual ~Panel() = default;
};
class EmptyPanel final : public Panel {
public:
void click(State& state) override {return;};
void display(State& state, sf::Window& window, sf::FloatRect area) override {return;};
void click(Screen& screen) override {return;};
void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) override {return;};
};
class CategoryPanel final : public Panel {
public:
CategoryPanel(const std::string& t_label) : label(t_label) {};
void click(State& state) override;
void display(State& state, sf::Window& window, sf::FloatRect area) override;
void click(Screen& screen) override;
void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) override;
private:
std::string label;
};
@ -34,8 +38,8 @@ namespace MusicSelect {
class SongPanel final : public Panel {
public:
SongPanel(const Data::Song& t_song) : song(t_song) {};
void click(State& state) override;
void display(State& state, sf::Window& window, sf::FloatRect area) override;
void click(Screen& screen) override;
void draw(Resources& resources, sf::RenderTarget& target, sf::FloatRect area) override;
private:
const Data::Song& song;
};

View File

@ -0,0 +1,8 @@
#include "Resources.hpp"
MusicSelect::Resources::Resources() {
if (not noto_sans_medium.loadFromFile("assets/fonts/NotoSans-Medium.ttf")) {
throw std::runtime_error("Unable to load assets/fonts/NotoSans-Medium.ttf");
}
}

View File

@ -1,15 +1,13 @@
#pragma once
#include <unordered_map>
#include <SFML/Graphics.hpp>
#include "../../Resources/CoverAtlas.hpp"
namespace MusicSelect {
// Holds the fonts, graphics and sounds needed by all of the MusicSelect Screen
struct Resources {
Resources();
Textures::CoverAltas cover_previews;
std::unordered_map<std::string, sf::Font> fonts;
sf::Font noto_sans_medium;
};
}
}

View File

@ -41,4 +41,33 @@ MusicSelect::Ribbon MusicSelect::Ribbon::title_sort(const Data::SongList& song_l
}
}
return ribbon;
}
}
MusicSelect::Ribbon MusicSelect::Ribbon::test_sort() {
Ribbon ribbon;
ribbon.layout.push_back(
{
std::make_unique<EmptyPanel>(),
std::make_unique<CategoryPanel>("A"),
std::make_unique<CategoryPanel>("truc")
}
);
for (size_t i = 0; i < 3; i++) {
ribbon.layout.push_back(
{
std::make_unique<EmptyPanel>(),
std::make_unique<EmptyPanel>(),
std::make_unique<EmptyPanel>()
}
);
}
return ribbon;
}
const std::unique_ptr<MusicSelect::Panel>& MusicSelect::Ribbon::at(unsigned int button_index) const {
return (
layout
.at((position + (button_index % 4)) % layout.size())
.at(button_index / 4)
);
}

View File

@ -10,8 +10,11 @@ namespace MusicSelect {
public:
Ribbon();
static Ribbon title_sort(const Data::SongList& song_list);
static Ribbon test_sort();
const auto& get_layout() {return layout;};
const std::unique_ptr<MusicSelect::Panel>& at(unsigned int button_index) const;
private:
std::vector<std::array<std::unique_ptr<Panel>,3>> layout;
unsigned int position = 0;
};
}

View File

@ -1,8 +0,0 @@
#include "State.hpp"
#include <algorithm>
#include <map>
MusicSelect::State::State(const Data::SongList& song_list) {
ribbon = MusicSelect::Ribbon::title_sort(song_list);
}

View File

@ -1,22 +0,0 @@
#pragma once
#include <array>
#include <functional>
#include <optional>
#include <vector>
#include "../Data/SongList.hpp"
#include "Panel.hpp"
#include "Ribbon.hpp"
namespace MusicSelect {
// Holds everything related to the displaying state of the MusicSelect screen
struct State {
State(const Data::SongList& song_list);
// The ribbon is the moving part or the music select screen
Ribbon ribbon;
unsigned int ribbon_position;
std::optional<std::reference_wrapper<SongPanel>> selected_panel;
};
}