diff --git a/.gitignore b/.gitignore index 71f32ab..f40fc7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,77 +1,7 @@ # This file is used to ignore files which are generated # ---------------------------------------------------------------------------- - +build SFML* -CMake* - -*~ -*.autosave -*.a -*.core -*.moc -*.o -*.obj -*.orig -*.rej -*.so -*.so.* -*_pch.h.cpp -*_resource.rc -*.qm -.#* -*.*# -core -!core/ -tags -.DS_Store -.directory -*.debug -Makefile* -*.prl -*.app -moc_*.cpp -ui_*.h -qrc_*.cpp -Thumbs.db -*.res -*.rc -/.qmake.cache -/.qmake.stash - -# qtcreator generated files -*.pro.user* - -# xemacs temporary files -*.flc - -# Vim temporary files -.*.swp - -# Visual Studio generated files -*.ib_pdb_index -*.idb -*.ilk -*.pdb -*.sln -*.suo -*.vcproj -*vcproj.*.*.user -*.ncb -*.sdf -*.opensdf -*.vcxproj -*vcxproj.* - -# MinGW generated files -*.Debug -*.Release - -# Python byte code -*.pyc - -# Binaries -# -------- -*.dll -*.exe +*.user diff --git a/CMakeLists.txt b/CMakeLists.txt index 7dd3a17..325a359 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,9 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wpedantic -g") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build) + set(CMAKE_THREAD_LIBS_INIT "-lpthread") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") set(CMAKE_HAVE_THREADS_LIBRARY 1) @@ -13,7 +16,7 @@ set(CMAKE_THREAD_LIBS_INIT "-lpthread") set(CMAKE_USE_PTHREADS_INIT 1) set(THREADS_PREFER_PTHREAD_FLAG ON) -file(GLOB_RECURSE SOURCES "include/*.h" "src/*.cpp" "src/*.h") +file(GLOB_RECURSE SOURCES "src/main.cpp" "src/application/*.cpp" "src/application/*.h") add_executable(project-kyoku ${SOURCES}) option(SFML_BUILT "SFML_BUILT" ON) @@ -32,3 +35,20 @@ else() endif() include_directories(${SFML_INCL_DIR} ${CMAKE_SOURCE_DIR}/include) + +SET(CMAKE_INSTALL_PREFIX /) +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/modes/classicmode/CMakeLists.txt") + add_subdirectory(modes/classicmode) + target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/modes/classicmode/shared) + target_link_libraries(project-kyoku classicmode) +endif() +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/CMakeLists.txt") + add_subdirectory(tools) + target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/tools/shared) + target_link_libraries(project-kyoku tools) +endif() +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/core/CMakeLists.txt") + add_subdirectory(core) + target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/core/shared) + target_link_libraries(project-kyoku core) +endif() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt new file mode 100644 index 0000000..1ab5eda --- /dev/null +++ b/core/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8.8) + +project(core) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared) + +file(GLOB_RECURSE HEADERS "shared/*.h") +file(GLOB_RECURSE SOURCES "src/*.cpp") + +add_library(core STATIC ${SOURCES} ${HEADERS}) +target_include_directories(core PRIVATE ${CMAKE_SOURCE_DIR}/tools/shared) +target_link_libraries(core tools) diff --git a/include/game/game.h b/core/shared/core/game.h similarity index 78% rename from include/game/game.h rename to core/shared/core/game.h index c9f9d88..98c1ac3 100644 --- a/include/game/game.h +++ b/core/shared/core/game.h @@ -1,8 +1,7 @@ #ifndef GAME_H #define GAME_H -#include -#include "game/inputtype.h" +#include "core/inputtype.h" class Game { diff --git a/include/game/inputtype.h b/core/shared/core/inputtype.h similarity index 100% rename from include/game/inputtype.h rename to core/shared/core/inputtype.h diff --git a/core/shared/core/note.h b/core/shared/core/note.h new file mode 100644 index 0000000..9f48b61 --- /dev/null +++ b/core/shared/core/note.h @@ -0,0 +1,28 @@ +#pragma once + +#include "core/inputtype.h" + +class Note +{ +public: + explicit Note(microsec perfect_offset) : + _perfect_offset(perfect_offset) {} + virtual ~Note() = default; + + virtual bool isActive() const = 0; + virtual void update(const microsec& music_offset) = 0; + virtual void input(PlayerInput&& inputdata) = 0; + virtual void draw() const = 0; + + virtual void putToGame(const microsec& offset) = 0; + virtual bool isInGame() const = 0; + virtual bool shouldRemove() const = 0; + + const microsec& offset() const noexcept + { + return _perfect_offset; + } + +protected: + microsec _perfect_offset; +}; diff --git a/include/game/precisionevaluator.h b/core/shared/core/precisionevaluator.h similarity index 99% rename from include/game/precisionevaluator.h rename to core/shared/core/precisionevaluator.h index 69ca971..416648c 100644 --- a/include/game/precisionevaluator.h +++ b/core/shared/core/precisionevaluator.h @@ -2,6 +2,7 @@ #define PRECISIONEVALUATOR_H #include "tools/mathutils.h" + #include #include #include diff --git a/core/shared/core/timeline.h b/core/shared/core/timeline.h new file mode 100644 index 0000000..ef65960 --- /dev/null +++ b/core/shared/core/timeline.h @@ -0,0 +1,188 @@ +#pragma once + +#include +#include +#include + +#include "tools/mathutils.h" +#include "core/note.h" + +template ::value>> +class Timeline +{ +public: + explicit Timeline() : + _current_offset(0) + {} + + typedef typename std::vector::const_iterator Iterator; + + void setNotes(const std::vector& notes, const microsec& visibility) + { + _visibility_offset = visibility; + _timeline = std::move(notes); + + _top_note = _timeline.begin(); + expire(_first_visible_note); + expire(_last_visible_note); + expire(_active_note); + + fetchVisibleNotes(); + } + + inline void clear() + { + for (auto& note : _timeline) + delete note; + + _timeline.clear(); + } + + void update(const microsec& offset) + { + _current_offset = offset; + + checkCurrentActiveNote(); + checkForNextActiveNote(); + updateVisibleSprites(_current_offset); + } + + void drawVisibleNotes() const + { + if (nothingToDraw()) + return; + + std::for_each(_first_visible_note, _last_visible_note, + [](const auto& note) + { + note->draw(); + }); + } + + void fetchVisibleNotes() + { + findLastVisibleNote(_current_offset); + findFirstVisibleNote(); + } + + void findLastVisibleNote(const microsec& music_offset) + { + Iterator note_iterator = _top_note; + while (isVisiblyClose(note_iterator, music_offset)) + { + if (nothingToDraw()) + _first_visible_note = note_iterator; + + auto note = *note_iterator; + + if (!note->isInGame()) + note->putToGame(music_offset); + + ++note_iterator; + } + + _last_visible_note = note_iterator; + } + + void findFirstVisibleNote() + { + if (nothingToDraw()) + return; + + auto note_iterator = _first_visible_note; + while (note_iterator != _last_visible_note) + { + auto note = *note_iterator; + if (note->shouldRemove()) + ++_first_visible_note; + + ++note_iterator; + } + } + + inline Iterator getActiveNote() noexcept + { + return _active_note; + } + + inline bool isExpired(const Iterator& iterator) const + { + return iterator == _timeline.end(); + } + + inline void expire(Iterator& iterator) + { + iterator = _timeline.end(); + } + +private: + std::vector _input_intervals; + std::vector _timeline; + microsec _visibility_offset; + microsec _current_offset; + + void updateVisibleSprites(const microsec& music_offset) + { + if (nothingToDraw()) + return; + + std::for_each(_first_visible_note, _last_visible_note, + [&music_offset](const auto& note) + { + note->update(music_offset); + }); + } + + void checkCurrentActiveNote() + { + if (isExpired(_active_note)) + return; + + auto note = *_active_note; + + if (!note->isActive()) + { + expire(_active_note); + ++_top_note; + } + } + + void checkForNextActiveNote() + { + if (!isExpired(_active_note)) + return; + + auto top_note = *_top_note; + if (top_note->isActive()) + _active_note = _top_note; + } + + inline bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const + { + return ((*iterator)->offset() - _visibility_offset) <= music_offset; + } + + inline bool nothingToDraw() const noexcept + { + return isExpired(_first_visible_note); + } + + /* Difference between top and active note is that + * top note is the note handling input right now + * OR it's the closest note from current music offset + * position, not necessarily active. A note stops being top only + * after dying or being tapped by player, even if it's already + * past her perfect offset. + * + * Meanwhile active note is the note which is currently handling + * player input for grade. + * + * An active note is always top note but a top note + * is not always active note. + * */ + + Iterator _top_note; + Iterator _active_note; + Iterator _last_visible_note; + Iterator _first_visible_note; +}; diff --git a/include/game/timeline.h b/include/game/timeline.h deleted file mode 100644 index b939ea2..0000000 --- a/include/game/timeline.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TIMELINE_H -#define TIMELINE_H - -#include "tools/mathutils.h" - -#include -#include - -class Note; - -class Timeline -{ -public: - virtual ~Timeline() = default; - - virtual void update(const microsec& offset) = 0; - virtual void clear() = 0; - - virtual void drawVisibleNotes() const = 0; -}; - -#endif // TIMELINE_H diff --git a/include/game/sprite.h b/include/sprite.h similarity index 100% rename from include/game/sprite.h rename to include/sprite.h diff --git a/include/game/spritecontainer.h b/include/spritecontainer.h similarity index 100% rename from include/game/spritecontainer.h rename to include/spritecontainer.h diff --git a/include/gui/state.h b/include/state.h similarity index 100% rename from include/gui/state.h rename to include/state.h diff --git a/include/tools/music.h b/include/tools/music.h deleted file mode 100644 index be9d368..0000000 --- a/include/tools/music.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "tools/mathutils.h" -#include - -class Music -{ -public: - virtual ~Music() = default; - - virtual bool openFromFile(const std::string& filepath) = 0; - - virtual void play() = 0; - virtual void pause() = 0; - virtual void stop() = 0; - - virtual void setVolume(int volume) = 0; - - virtual void setOffset(const microsec& offset) = 0; - virtual microsec fetchOffset() = 0; -}; diff --git a/modes/classicmode/CMakeLists.txt b/modes/classicmode/CMakeLists.txt new file mode 100644 index 0000000..1012ded --- /dev/null +++ b/modes/classicmode/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.8.8) + +project(classicmode) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +include_directories(${CMAKE_SOURCE_DIR}/shared) + +file(GLOB_RECURSE HEADERS "shared/*.h") +file(GLOB_RECURSE SOURCES "editor/*.h" "editor/*.cpp" "game/*.h" "game/*.cpp" "./classicfactory.cpp") + +add_library(classicmode STATIC ${SOURCES} ${HEADERS}) +target_include_directories(classicmode PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(classicmode PRIVATE ${CMAKE_SOURCE_DIR}/tools/shared) +target_include_directories(classicmode PRIVATE ${CMAKE_SOURCE_DIR}/core/shared) +target_link_libraries(classicmode tools core) diff --git a/modes/classicmode/classicfactory.cpp b/modes/classicmode/classicfactory.cpp new file mode 100644 index 0000000..6d60773 --- /dev/null +++ b/modes/classicmode/classicfactory.cpp @@ -0,0 +1,11 @@ +#include "shared/classicmode/classicfactory.h" +#include "game/classicgame.h" +#include "game/classicgraphicsmanager.h" +#include "tools/music.h" + +#include + +std::unique_ptr classic::init(sf::RenderWindow& game_window) +{ + return std::make_unique(std::make_unique(game_window), std::make_unique()); +} diff --git a/src/classicgame/classicactions.h b/modes/classicmode/game/classicactions.h similarity index 100% rename from src/classicgame/classicactions.h rename to modes/classicmode/game/classicactions.h diff --git a/src/classicgame/classicanimationscenario.h b/modes/classicmode/game/classicanimationscenario.h similarity index 100% rename from src/classicgame/classicanimationscenario.h rename to modes/classicmode/game/classicanimationscenario.h diff --git a/src/classicgame/classicdyinganimationscenario.cpp b/modes/classicmode/game/classicdyinganimationscenario.cpp similarity index 100% rename from src/classicgame/classicdyinganimationscenario.cpp rename to modes/classicmode/game/classicdyinganimationscenario.cpp diff --git a/src/classicgame/classicdyinganimationscenario.h b/modes/classicmode/game/classicdyinganimationscenario.h similarity index 100% rename from src/classicgame/classicdyinganimationscenario.h rename to modes/classicmode/game/classicdyinganimationscenario.h diff --git a/src/classicgame/classicflyinganimationscenario.cpp b/modes/classicmode/game/classicflyinganimationscenario.cpp similarity index 100% rename from src/classicgame/classicflyinganimationscenario.cpp rename to modes/classicmode/game/classicflyinganimationscenario.cpp diff --git a/src/classicgame/classicflyinganimationscenario.h b/modes/classicmode/game/classicflyinganimationscenario.h similarity index 100% rename from src/classicgame/classicflyinganimationscenario.h rename to modes/classicmode/game/classicflyinganimationscenario.h diff --git a/src/classicgame/classicgame.cpp b/modes/classicmode/game/classicgame.cpp similarity index 77% rename from src/classicgame/classicgame.cpp rename to modes/classicmode/game/classicgame.cpp index c68fc3b..674691a 100644 --- a/src/classicgame/classicgame.cpp +++ b/modes/classicmode/game/classicgame.cpp @@ -1,15 +1,10 @@ #include "classicgame.h" -#include "classictimeline.h" #include "classicnote.h" #include "classicmapcreator.h" -#include "classicnotemanager.h" #include "tools/music.h" -#include ClassicGame::ClassicGame(std::shared_ptr&& manager, std::unique_ptr&& music) : _graphics_manager(std::move(manager)), - _note_manager(std::make_unique(_graphics_manager)), - _timeline(std::make_unique(_note_manager)), _music(std::move(music)), _is_paused(false) { @@ -66,7 +61,7 @@ void ClassicGame::run() _music->openFromFile("METEOR.flac"); _music->setVolume(10); _music->play(); - _timeline->setNotes(std::move(beatmap.notes), beatmap.visibility_offset); + _timeline.setNotes(beatmap.notes, beatmap.visibility_offset); } void ClassicGame::input(PlayerInput&& inputdata) @@ -97,15 +92,15 @@ void ClassicGame::input(PlayerInput&& inputdata) } } - auto note_it = _timeline->getActiveNote(); + auto note_it = _timeline.getActiveNote(); - if (!_timeline->isExpired(note_it)) + if (!_timeline.isExpired(note_it)) { auto note = (*note_it); - _note_manager->input(note, std::move(inputdata)); + note->input(std::move(inputdata)); _slap.play(); - if (note->hold && _note_manager->allElementsPressed(note)) // also check for Type + if (note->isHold() && note->allElementsPressed()) // also check for Type { _notes_on_hold.emplace_back(note); std::cout << "HOLD initited by " << inputdata.event.key.code << '\n'; @@ -116,11 +111,10 @@ void ClassicGame::input(PlayerInput&& inputdata) case sf::Event::KeyReleased: { - const auto& note_manager = _note_manager; bool key_match = std::any_of(_notes_on_hold.begin(), _notes_on_hold.end(), - [¬e_manager, key=inputdata.event.key.code](const auto& note) + [key=inputdata.event.key.code](const auto& note) { - return note_manager->isPressedAs(note, key); + return note->isPressedAs(key); }); if (key_match) @@ -136,11 +130,11 @@ void ClassicGame::input(PlayerInput&& inputdata) void ClassicGame::update() { - _timeline->update(_music->fetchOffset()); - _timeline->fetchVisibleNotes(); + _timeline.update(_music->fetchOffset()); + _timeline.fetchVisibleNotes(); } void ClassicGame::draw() const { - _timeline->drawVisibleNotes(); + _timeline.drawVisibleNotes(); } diff --git a/src/classicgame/classicgame.h b/modes/classicmode/game/classicgame.h similarity index 83% rename from src/classicgame/classicgame.h rename to modes/classicmode/game/classicgame.h index 0604eb1..cd2da10 100644 --- a/src/classicgame/classicgame.h +++ b/modes/classicmode/game/classicgame.h @@ -3,16 +3,18 @@ #include #include -#include "game/game.h" -#include "classicactions.h" + #include #include +#include "core/game.h" +#include "core/timeline.h" + +#include "classicnote.h" +#include "classicactions.h" + class Music; -class ClassicNote; -class ClassicTimeline; class ClassicGraphicsManager; -class ClassicNoteManager; class ClassicGame final : public Game { @@ -34,8 +36,7 @@ private: std::vector _notes_on_hold; std::shared_ptr _graphics_manager; - std::shared_ptr _note_manager; - std::unique_ptr _timeline; + Timeline _timeline; sf::SoundBuffer _slap_buffer; sf::Sound _slap; diff --git a/src/classicgame/classicgraphicsmanager.cpp b/modes/classicmode/game/classicgraphicsmanager.cpp similarity index 100% rename from src/classicgame/classicgraphicsmanager.cpp rename to modes/classicmode/game/classicgraphicsmanager.cpp diff --git a/src/classicgame/classicgraphicsmanager.h b/modes/classicmode/game/classicgraphicsmanager.h similarity index 94% rename from src/classicgame/classicgraphicsmanager.h rename to modes/classicmode/game/classicgraphicsmanager.h index 725d6fd..181032d 100644 --- a/src/classicgame/classicgraphicsmanager.h +++ b/modes/classicmode/game/classicgraphicsmanager.h @@ -1,6 +1,6 @@ #pragma once -#include "game/spritecontainer.h" +#include "spritecontainer.h" #include "classicactions.h" #include "classicspritefactory.h" diff --git a/src/classicgame/classicmapcreator.cpp b/modes/classicmode/game/classicmapcreator.cpp similarity index 51% rename from src/classicgame/classicmapcreator.cpp rename to modes/classicmode/game/classicmapcreator.cpp index 41ee3c6..8591a83 100644 --- a/src/classicgame/classicmapcreator.cpp +++ b/modes/classicmode/game/classicmapcreator.cpp @@ -35,43 +35,29 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const while (bpm_iterator < bpm_end) { - ClassicNote *note = new ClassicNote( - { - {input_intervals, bpm_iterator}, - {input_intervals}, - false, - ClassicNoteState::NONE, - { - ClassicNote::Element - { - {x, 390.}, - false, - sf::Keyboard::Unknown, - Type::UP, - {}, - {sf::Keyboard::W, sf::Keyboard::Up}, - {nullptr}, - {} - } - } - }); - - note->elements[0].animations[ClassicNoteState::NONE] = nullptr; - note->elements[0].animations[ClassicNoteState::FLYING] = std::make_shared(); - note->elements[0].animations[ClassicNoteState::ACTIVE] = note->elements[0].animations[ClassicNoteState::FLYING]; - note->elements[0].animations[ClassicNoteState::DYING] = std::make_shared(); - note->elements[0].animations[ClassicNoteState::DEAD] = nullptr; + ClassicNote::ClassicNoteInitializer init; + ClassicNote::ClassicNoteInitializer::Element element; + init.intervals = input_intervals; + init.perfect_offset = bpm_iterator; + init.hold = false; + + element.coordinates = {x, 390.}; + element.falling_curve_interpolation = {}; + element.keys = {sf::Keyboard::W, sf::Keyboard::Up}; + element.type = Type::UP; if (counter == 0) { - note->hold = true; - note->elements[0].available_keys = {sf::Keyboard::D, sf::Keyboard::Right}; - note->elements[0].type = Type::RIGHT; + init.hold = true; + element.keys = {sf::Keyboard::D, sf::Keyboard::Right}; + element.type = Type::RIGHT; } --counter; - notes.emplace_back(note); + init.elements = {element}; + + notes.emplace_back(new ClassicNote(std::move(init), _graphics_manager)); bpm_iterator += tempo_interval; x += 70; @@ -82,3 +68,4 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const return {std::move(notes), note_input_offset * 12}; } + diff --git a/src/classicgame/classicmapcreator.h b/modes/classicmode/game/classicmapcreator.h similarity index 95% rename from src/classicgame/classicmapcreator.h rename to modes/classicmode/game/classicmapcreator.h index bc0f41f..8a92ce8 100644 --- a/src/classicgame/classicmapcreator.h +++ b/modes/classicmode/game/classicmapcreator.h @@ -4,6 +4,8 @@ #include #include "tools/mathutils.h" +#include "core/note.h" + #include "classicgraphicsmanager.h" struct Beatmap diff --git a/modes/classicmode/game/classicnote.cpp b/modes/classicmode/game/classicnote.cpp new file mode 100644 index 0000000..bfc27a2 --- /dev/null +++ b/modes/classicmode/game/classicnote.cpp @@ -0,0 +1,162 @@ +#include "classicnote.h" +#include "classicsprite.h" +#include "classicgraphicsmanager.h" + +// Replace with interface by dependency injection +#include "classicflyinganimationscenario.h" +#include "classicdyinganimationscenario.h" +// + +ClassicNote::ClassicNote(ClassicNoteInitializer &&init, const std::shared_ptr& manager) : + Note(init.perfect_offset), + _evaluator(init.intervals, _perfect_offset), + _graphics_manager(manager), + _state(State::NONE) +{ + _elements.resize(init.elements.size()); + _isHold = init.hold; + + for (std::size_t i = 0; i < _elements.size(); ++i) + { + _elements[i].keys = init.elements[i].keys; + _elements[i].coordinates = init.elements[i].coordinates; + _elements[i].type = init.elements[i].type; + + // Animations will be injected into note. + _elements[i].animations[State::NONE] = nullptr; + _elements[i].animations[State::FLYING] = std::make_shared(); + _elements[i].animations[State::ACTIVE] = _elements[i].animations[State::FLYING]; + _elements[i].animations[State::DYING] = std::make_shared(); + _elements[i].animations[State::DEAD] = nullptr; + } +} + +bool ClassicNote::isActive() const +{ + return _state == State::ACTIVE; +} + +void ClassicNote::putToGame(const microsec &music_offset) +{ + _state = State::FLYING; + + for (auto& element : _elements) + { + element.sprite = _graphics_manager->getSprite(element.type); + element.sprite->setCoordinates(element.coordinates, 0., 9.); + element.animations[_state]->launch(element.sprite, music_offset, offset()); + } +} + +bool ClassicNote::isInGame() const +{ + return _state == State::FLYING + || _state == State::ACTIVE + || _state == State::DYING; +} + +bool ClassicNote::shouldRemove() const +{ + return _state == State::DEAD; +} + +void ClassicNote::update(const microsec& music_offset) +{ + switch (_state) + { + default: return; + break; + + case State::FLYING: + if (_evaluator.isActive(music_offset)) + _state = State::ACTIVE; + break; + + case State::DYING: + if (_elements[0].animations[_state]->isDone()) + _state = State::DEAD; + break; + + case State::ACTIVE: + if (!_evaluator.isActive(music_offset)) + { + _state = State::DYING; + for (auto& element : _elements) + element.animations[_state]->launch(element.sprite, music_offset, offset()); + } + break; + } + + for (auto& element : _elements) + if (element.animations[_state]) + element.animations[_state]->update(music_offset); +} + +void ClassicNote::input(PlayerInput&& inputdata) +{ + auto grade = ClassicNote::Grade::BAD; + + bool input_valid = std::any_of(_elements.begin(), _elements.end(), + [inputdata=inputdata](auto& element) + { + if (element.pressed) + return false; + + auto key_iterator = std::find(element.keys.begin(), element.keys.end(), inputdata.event.key.code); + bool found_key = key_iterator != element.keys.end(); + if (found_key) + { + element.pressed = true; + element.pressed_as = inputdata.event.key.code; + } + + return found_key; + }); + + bool all_pressed = allElementsPressed(); + + if (all_pressed) + grade = _evaluator.calculatePrecision(inputdata.timestamp); + + if (all_pressed || !input_valid) + { + _state = State::DYING; + for (auto& element : _elements) + element.animations[_state]->launch(element.sprite, inputdata.timestamp, offset()); + } + + std::cout << "User input: " << static_cast(grade) << "\n"; +} + +void ClassicNote::draw() const +{ + for (std::size_t i = 0; i < _elements.size(); ++i) + { + if (i >= 1) + _graphics_manager->drawLine(_elements[i-1].sprite->trailCoordinates(), _elements[i].sprite->trailCoordinates()); + _graphics_manager->draw(_elements[i].sprite); + } +} + +bool ClassicNote::isHold() const +{ + return _isHold; +} + +bool ClassicNote::allElementsPressed() const +{ + return std::all_of(_elements.begin(), _elements.end(), + [](const auto& element) + { + return element.pressed; + }); +} + +bool ClassicNote::isPressedAs(sf::Keyboard::Key key) const +{ + return std::any_of(_elements.begin(), _elements.end(), + [key=key](const auto& element) + { + return key == element.pressed_as; + }); +} diff --git a/modes/classicmode/game/classicnote.h b/modes/classicmode/game/classicnote.h new file mode 100644 index 0000000..25c7733 --- /dev/null +++ b/modes/classicmode/game/classicnote.h @@ -0,0 +1,89 @@ +#pragma once + +#include "core/note.h" +#include "core/precisionevaluator.h" +#include "classicactions.h" + +#include +#include + +class ClassicSprite; +class ClassicGraphicsManager; +class ClassicAnimationScenario; + +class ClassicNote : public Note +{ +public: + + enum class Grade + { + PERFECT, + GOOD, + BAD + }; + + enum State + { + NONE, + + FLYING, + ACTIVE, + DYING, + DEAD + }; + + struct ClassicNoteInitializer + { + std::vector intervals; + microsec perfect_offset; + bool hold; + + struct Element + { + Type type; + Coordinates coordinates; + std::vector falling_curve_interpolation; + std::array keys; + }; + + std::vector elements; + }; + + explicit ClassicNote(ClassicNoteInitializer&& init, const std::shared_ptr& manager); + virtual ~ClassicNote() = default; + + virtual bool isActive() const override; + virtual void update(const microsec &music_offset) override; + virtual void input(PlayerInput&& inputdata) override; + virtual void putToGame(const microsec &music_offset) override; + virtual bool isInGame() const override; + virtual bool shouldRemove() const override; + virtual void draw() const override; + + bool isHold() const; + bool allElementsPressed() const; + bool isPressedAs(sf::Keyboard::Key key) const; + +private: + + struct NoteElement + { + std::shared_ptr sprite; + std::array, 5> animations; + + std::array keys; + Coordinates coordinates; // Each note may consist of several buttons. + Type type; // For example, ↑ → or ↓ → ← + // Note Element represents this idea. + bool pressed = false; // Each ending button in such sequence + sf::Keyboard::Key pressed_as; // is an element. + }; + + std::vector _elements; + + const PrecisionEvaluator _evaluator; + const std::shared_ptr _graphics_manager; + + State _state; + bool _isHold; +}; diff --git a/src/classicgame/classicsprite.cpp b/modes/classicmode/game/classicsprite.cpp similarity index 100% rename from src/classicgame/classicsprite.cpp rename to modes/classicmode/game/classicsprite.cpp diff --git a/src/classicgame/classicsprite.h b/modes/classicmode/game/classicsprite.h similarity index 89% rename from src/classicgame/classicsprite.h rename to modes/classicmode/game/classicsprite.h index 5397af7..b79b2bb 100644 --- a/src/classicgame/classicsprite.h +++ b/modes/classicmode/game/classicsprite.h @@ -1,9 +1,9 @@ #pragma once #include "tools/mathutils.h" -#include "game/sprite.h" -#include "SFML/Graphics/RectangleShape.hpp" -#include "SFML/Graphics/Text.hpp" +#include "sprite.h" +#include +#include class ClassicSprite : public Sprite, public sf::Drawable { diff --git a/src/classicgame/classicspritefactory.h b/modes/classicmode/game/classicspritefactory.h similarity index 100% rename from src/classicgame/classicspritefactory.h rename to modes/classicmode/game/classicspritefactory.h diff --git a/modes/classicmode/shared/classicmode/classicfactory.h b/modes/classicmode/shared/classicmode/classicfactory.h new file mode 100644 index 0000000..29b4a9f --- /dev/null +++ b/modes/classicmode/shared/classicmode/classicfactory.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +class Game; + +namespace sf { class RenderWindow; } + +namespace classic +{ + std::unique_ptr init(sf::RenderWindow &game_window); +} diff --git a/src/application.cpp b/src/application/application.cpp similarity index 85% rename from src/application.cpp rename to src/application/application.cpp index 55ed761..d0f7837 100644 --- a/src/application.cpp +++ b/src/application/application.cpp @@ -1,14 +1,12 @@ #include "application.h" -#include "game/inputtype.h" +#include "core/inputtype.h" -#include "classicgame/classicgame.h" -#include "classicgame/classicgraphicsmanager.h" +#include "mainmenu.h" +#include "gamestate.h" +#include "editor.h" -#include "gui/mainmenu.h" -#include "gui/gamestate.h" -#include "gui/editor.h" - -#include "tools/musicsfml.h" +#include "tools/music.h" +#include "classicmode/classicfactory.h" #include @@ -19,7 +17,7 @@ Application::Application() : { _font_holder.load(Fonts::Id::GUI, "SourceCodePro-Regular.ttf"); - _game = std::make_unique(std::make_unique(_game_window), std::make_unique()); + _game = classic::init(_game_window); _game_window.setFramerateLimit(60); _game_window.setKeyRepeatEnabled(false); @@ -36,7 +34,7 @@ Application::Application() : const auto main_menu = std::make_shared(_game_window, std::move(callbacks), _font_holder); const auto game_state = std::make_shared(_game_window, _game, GameState::Callbacks()); - const auto editor = std::make_shared(_game_window, std::move(editor_callbacks), std::make_unique(), _font_holder); + const auto editor = std::make_shared(_game_window, std::move(editor_callbacks), std::make_unique(), _font_holder); _states[GUIState::Tag::MAIN_MENU] = main_menu; _states[GUIState::Tag::GAME] = game_state; diff --git a/include/application.h b/src/application/application.h similarity index 83% rename from include/application.h rename to src/application/application.h index 5d690d1..e474dff 100644 --- a/include/application.h +++ b/src/application/application.h @@ -1,14 +1,18 @@ #ifndef APPLICATION_H #define APPLICATION_H +#include #include #include + +#include +#include #include #include #include -#include "game/game.h" -#include "gui/state.h" +#include "core/game.h" +#include "state.h" #include "tools/resourceholder.h" @@ -25,7 +29,6 @@ private: std::array, GUIState::Tag::AMOUNT> _states; std::vector> _state_stack; - sf::RenderWindow _game_window; std::shared_ptr _game; diff --git a/src/gui/editor.cpp b/src/application/editor.cpp similarity index 100% rename from src/gui/editor.cpp rename to src/application/editor.cpp diff --git a/src/gui/editor.h b/src/application/editor.h similarity index 97% rename from src/gui/editor.h rename to src/application/editor.h index e378838..7238319 100644 --- a/src/gui/editor.h +++ b/src/application/editor.h @@ -1,6 +1,6 @@ #pragma once -#include "gui/state.h" +#include "state.h" #include "tools/music.h" #include "tools/resourceholder.h" #include diff --git a/src/gui/gamestate.cpp b/src/application/gamestate.cpp similarity index 96% rename from src/gui/gamestate.cpp rename to src/application/gamestate.cpp index d7fb41b..cb135b3 100644 --- a/src/gui/gamestate.cpp +++ b/src/application/gamestate.cpp @@ -2,7 +2,7 @@ #include "widgets/button.h" #include "widgets/group.h" -#include "game/game.h" +#include "core/game.h" GameState::GameState(sf::RenderWindow& game_window, const std::shared_ptr& game, Callbacks&& callbacks) : diff --git a/src/gui/gamestate.h b/src/application/gamestate.h similarity index 97% rename from src/gui/gamestate.h rename to src/application/gamestate.h index d4482d2..a282e61 100644 --- a/src/gui/gamestate.h +++ b/src/application/gamestate.h @@ -1,6 +1,6 @@ #pragma once -#include "gui/state.h" +#include "state.h" #include class Group; diff --git a/src/gui/mainmenu.cpp b/src/application/mainmenu.cpp similarity index 100% rename from src/gui/mainmenu.cpp rename to src/application/mainmenu.cpp diff --git a/src/gui/mainmenu.h b/src/application/mainmenu.h similarity index 96% rename from src/gui/mainmenu.h rename to src/application/mainmenu.h index f5fee9e..ce75467 100644 --- a/src/gui/mainmenu.h +++ b/src/application/mainmenu.h @@ -1,6 +1,6 @@ #pragma once -#include "gui/state.h" +#include "state.h" #include "tools/resourceholder.h" #include diff --git a/src/gui/widgets/bpmcalculatorwidget.cpp b/src/application/widgets/bpmcalculatorwidget.cpp similarity index 100% rename from src/gui/widgets/bpmcalculatorwidget.cpp rename to src/application/widgets/bpmcalculatorwidget.cpp diff --git a/src/gui/widgets/bpmcalculatorwidget.h b/src/application/widgets/bpmcalculatorwidget.h similarity index 100% rename from src/gui/widgets/bpmcalculatorwidget.h rename to src/application/widgets/bpmcalculatorwidget.h diff --git a/src/gui/widgets/bpmslider.cpp b/src/application/widgets/bpmslider.cpp similarity index 100% rename from src/gui/widgets/bpmslider.cpp rename to src/application/widgets/bpmslider.cpp diff --git a/src/gui/widgets/bpmslider.h b/src/application/widgets/bpmslider.h similarity index 100% rename from src/gui/widgets/bpmslider.h rename to src/application/widgets/bpmslider.h diff --git a/src/gui/widgets/button.cpp b/src/application/widgets/button.cpp similarity index 99% rename from src/gui/widgets/button.cpp rename to src/application/widgets/button.cpp index 742b6bb..681e600 100644 --- a/src/gui/widgets/button.cpp +++ b/src/application/widgets/button.cpp @@ -1,5 +1,6 @@ #include "button.h" #include + Button::Button(const std::string &text, const std::shared_ptr& font, unsigned int font_size) : _font(font) { diff --git a/src/gui/widgets/button.h b/src/application/widgets/button.h similarity index 100% rename from src/gui/widgets/button.h rename to src/application/widgets/button.h diff --git a/src/gui/widgets/cascademenubutton.cpp b/src/application/widgets/cascademenubutton.cpp similarity index 100% rename from src/gui/widgets/cascademenubutton.cpp rename to src/application/widgets/cascademenubutton.cpp diff --git a/src/gui/widgets/cascademenubutton.h b/src/application/widgets/cascademenubutton.h similarity index 100% rename from src/gui/widgets/cascademenubutton.h rename to src/application/widgets/cascademenubutton.h diff --git a/src/gui/widgets/group.cpp b/src/application/widgets/group.cpp similarity index 100% rename from src/gui/widgets/group.cpp rename to src/application/widgets/group.cpp diff --git a/src/gui/widgets/group.h b/src/application/widgets/group.h similarity index 100% rename from src/gui/widgets/group.h rename to src/application/widgets/group.h diff --git a/src/gui/widgets/menubar.cpp b/src/application/widgets/menubar.cpp similarity index 100% rename from src/gui/widgets/menubar.cpp rename to src/application/widgets/menubar.cpp diff --git a/src/gui/widgets/menubar.h b/src/application/widgets/menubar.h similarity index 100% rename from src/gui/widgets/menubar.h rename to src/application/widgets/menubar.h diff --git a/src/gui/widgets/menudrop.cpp b/src/application/widgets/menudrop.cpp similarity index 100% rename from src/gui/widgets/menudrop.cpp rename to src/application/widgets/menudrop.cpp diff --git a/src/gui/widgets/menudrop.h b/src/application/widgets/menudrop.h similarity index 100% rename from src/gui/widgets/menudrop.h rename to src/application/widgets/menudrop.h diff --git a/src/gui/widgets/menuseparator.cpp b/src/application/widgets/menuseparator.cpp similarity index 100% rename from src/gui/widgets/menuseparator.cpp rename to src/application/widgets/menuseparator.cpp diff --git a/src/gui/widgets/menuseparator.h b/src/application/widgets/menuseparator.h similarity index 100% rename from src/gui/widgets/menuseparator.h rename to src/application/widgets/menuseparator.h diff --git a/src/gui/widgets/pushbutton.cpp b/src/application/widgets/pushbutton.cpp similarity index 100% rename from src/gui/widgets/pushbutton.cpp rename to src/application/widgets/pushbutton.cpp diff --git a/src/gui/widgets/pushbutton.h b/src/application/widgets/pushbutton.h similarity index 100% rename from src/gui/widgets/pushbutton.h rename to src/application/widgets/pushbutton.h diff --git a/src/gui/widgets/widget.cpp b/src/application/widgets/widget.cpp similarity index 100% rename from src/gui/widgets/widget.cpp rename to src/application/widgets/widget.cpp diff --git a/src/gui/widgets/widget.h b/src/application/widgets/widget.h similarity index 100% rename from src/gui/widgets/widget.h rename to src/application/widgets/widget.h diff --git a/src/gui/widgets/window.cpp b/src/application/widgets/window.cpp similarity index 100% rename from src/gui/widgets/window.cpp rename to src/application/widgets/window.cpp diff --git a/src/gui/widgets/window.h b/src/application/widgets/window.h similarity index 100% rename from src/gui/widgets/window.h rename to src/application/widgets/window.h diff --git a/src/classicgame/classicnote.h b/src/classicgame/classicnote.h deleted file mode 100644 index 3507002..0000000 --- a/src/classicgame/classicnote.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "classicactions.h" -#include "game/precisionevaluator.h" - -#include "SFML/Window/Keyboard.hpp" - -#include -#include -#include - -enum class ClassicGrade -{ - PERFECT, - GOOD, - BAD -}; - -enum ClassicNoteState -{ - NONE, - - FLYING, - ACTIVE, - DYING, - DEAD -}; - -class ClassicSprite; -class ClassicAnimationScenario; - -struct ClassicNote -{ - PrecisionEvaluator evaluator; - std::vector intervals; - bool hold = false; - - ClassicNoteState state = ClassicNoteState::NONE; - - struct Element - { - Coordinates coordinates; // Each note may consist of several buttons. - // For example, ↑ → or ↓ → ← - // Note Element represents this idea. - bool pressed = false; // Each ending button in such sequence - sf::Keyboard::Key pressed_as; // is an element. - - Type type = Type::NONE; - std::vector falling_curve_interpolation; - std::array available_keys; - std::shared_ptr sprite; - std::array, 5> animations; - }; - - std::vector elements; -}; diff --git a/src/classicgame/classicnotemanager.cpp b/src/classicgame/classicnotemanager.cpp deleted file mode 100644 index 9d33536..0000000 --- a/src/classicgame/classicnotemanager.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "classicnotemanager.h" -#include "classicsprite.h" -#include "classicgraphicsmanager.h" - -// Replace with interface by dependency injection -#include "classicflyinganimationscenario.h" -#include "classicdyinganimationscenario.h" -// - - -ClassicNoteManager::ClassicNoteManager(const std::shared_ptr& manager) : - _graphics_manager(manager) -{} - -ClassicNoteManager::~ClassicNoteManager() -{} - -bool ClassicNoteManager::isActive(const ClassicNote* note) const -{ - return note->state == ClassicNoteState::ACTIVE; -} - -void ClassicNoteManager::putToGame(ClassicNote* note, const microsec &music_offset) -{ - note->state = ClassicNoteState::FLYING; - - for (auto& element : note->elements) - { - element.sprite = _graphics_manager->getSprite(element.type); - element.sprite->setCoordinates(element.coordinates, 0., 9.); - element.animations[note->state]->launch(element.sprite, music_offset, note->evaluator.offset()); - } -} - -bool ClassicNoteManager::isInGame(const ClassicNote* note) const -{ - return note->state == ClassicNoteState::FLYING - || note->state == ClassicNoteState::ACTIVE - || note->state == ClassicNoteState::DYING; -} - -bool ClassicNoteManager::shouldRemove(const ClassicNote* note) const -{ - return note->state == ClassicNoteState::DEAD; -} - -void ClassicNoteManager::update(ClassicNote* note, const microsec& music_offset) -{ - switch (note->state) - { - default: return; - break; - - case ClassicNoteState::FLYING: - if (note->evaluator.isActive(music_offset)) - note->state = ClassicNoteState::ACTIVE; - break; - - case ClassicNoteState::DYING: - if (note->elements[0].animations[note->state]->isDone()) - note->state = ClassicNoteState::DEAD; - break; - - case ClassicNoteState::ACTIVE: - if (!note->evaluator.isActive(music_offset)) - { - note->state = ClassicNoteState::DYING; - for (auto& element : note->elements) - element.animations[note->state]->launch(element.sprite, music_offset, note->evaluator.offset()); - } - break; - } - - for (auto& element : note->elements) - if (element.animations[note->state]) - element.animations[note->state]->update(music_offset); -} - -void ClassicNoteManager::input(ClassicNote* note, PlayerInput&& inputdata) -{ - auto grade = ClassicGrade::BAD; - - bool input_valid = std::any_of(note->elements.begin(), note->elements.end(), - [inputdata=inputdata](auto& element) - { - if (element.pressed) - return false; - - auto key_iterator = std::find(element.available_keys.begin(), element.available_keys.end(), inputdata.event.key.code); - bool found_key = key_iterator != element.available_keys.end(); - if (found_key) - { - element.pressed = true; - element.pressed_as = inputdata.event.key.code; - } - - return found_key; - }); - - bool all_pressed = allElementsPressed(note); - - if (all_pressed) - grade = note->evaluator.calculatePrecision(inputdata.timestamp); - - if (all_pressed || !input_valid) - { - note->state = ClassicNoteState::DYING; - for (auto& element : note->elements) - element.animations[note->state]->launch(element.sprite, inputdata.timestamp, note->evaluator.offset()); - } - - std::cout << "User input: " << static_cast(grade) << "\n"; -} - -void ClassicNoteManager::draw(const ClassicNote* note) const -{ - for (std::size_t i = 0; i < note->elements.size(); ++i) - { - if (i >= 1) - _graphics_manager->drawLine(note->elements[i-1].sprite->trailCoordinates(), note->elements[i].sprite->trailCoordinates()); - _graphics_manager->draw(note->elements[i].sprite); - } -} - -bool ClassicNoteManager::allElementsPressed(const ClassicNote* note) const -{ - return std::all_of(note->elements.begin(), note->elements.end(), - [](const auto& element) - { - return element.pressed; - }); -} - -bool ClassicNoteManager::isPressedAs(const ClassicNote* note, sf::Keyboard::Key key) const -{ - return std::any_of(note->elements.begin(), note->elements.end(), - [key=key](const auto& element) - { - return key == element.pressed_as; - }); -} diff --git a/src/classicgame/classicnotemanager.h b/src/classicgame/classicnotemanager.h deleted file mode 100644 index 572c7fd..0000000 --- a/src/classicgame/classicnotemanager.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "game/inputtype.h" -#include "classicnote.h" -#include - -class ClassicGraphicsManager; - -class ClassicNoteManager -{ -public: - explicit ClassicNoteManager(const std::shared_ptr& manager); - ~ClassicNoteManager(); - - bool isActive(const ClassicNote* note) const; - void update(ClassicNote* note, const microsec &music_offset); - void input(ClassicNote* note, PlayerInput&& inputdata); - void putToGame(ClassicNote* note, const microsec &music_offset); - bool isInGame(const ClassicNote* note) const; - bool shouldRemove(const ClassicNote* note) const; - void draw(const ClassicNote* note) const; - - bool allElementsPressed(const ClassicNote* note) const; - bool isPressedAs(const ClassicNote* note, sf::Keyboard::Key key) const; - -private: - const std::shared_ptr _graphics_manager; -}; diff --git a/src/classicgame/classictimeline.cpp b/src/classicgame/classictimeline.cpp deleted file mode 100644 index eae3e32..0000000 --- a/src/classicgame/classictimeline.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include "classictimeline.h" -#include "classicnotemanager.h" -#include - -ClassicTimeline::ClassicTimeline(const std::shared_ptr& manager) : - _note_manager(manager), - _current_offset(0) -{} - -void ClassicTimeline::setNotes(std::vector &¬es, const microsec &visibility) -{ - _visibility_offset = visibility; - _timeline = std::move(notes); - - _top_note = _timeline.begin(); - expire(_first_visible_note); - expire(_last_visible_note); - expire(_active_note); - - fetchVisibleNotes(); -} - -ClassicTimeline::~ClassicTimeline() -{ - clear(); -} - -void ClassicTimeline::clear() -{ - for (auto& note : _timeline) - delete note; - - _timeline.clear(); -} - -void ClassicTimeline::update(const microsec& offset) -{ - _current_offset = offset; - - checkCurrentActiveNote(); - checkForNextActiveNote(); - updateVisibleSprites(_current_offset); -} - -void ClassicTimeline::checkCurrentActiveNote() -{ - if (isExpired(_active_note)) - return; - - auto note = *_active_note; - - if (!_note_manager->isActive(note)) - { - expire(_active_note); - ++_top_note; - } -} - -void ClassicTimeline::checkForNextActiveNote() -{ - if (!isExpired(_active_note)) - return; - - auto top_note = *_top_note; - if (_note_manager->isActive(top_note)) - _active_note = _top_note; -} - -void ClassicTimeline::updateVisibleSprites(const microsec& music_offset) -{ - if (nothingToDraw()) - return; - - const auto& note_manager = _note_manager; - std::for_each(_first_visible_note, _last_visible_note, - [¬e_manager, &music_offset](const auto& note) - { - note_manager->update(note, music_offset); - }); -} - -ClassicTimeline::Iterator ClassicTimeline::getActiveNote() noexcept -{ - return _active_note; -} - -bool ClassicTimeline::isExpired(const Iterator& iterator) const -{ - return iterator == _timeline.end(); -} - -void ClassicTimeline::expire(Iterator& iterator) -{ - iterator = _timeline.end(); -} - -bool ClassicTimeline::isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const -{ - return ((*iterator)->evaluator.offset() - _visibility_offset) <= music_offset; -} - -void ClassicTimeline::fetchVisibleNotes() -{ - findLastVisibleNote(_current_offset); - findFirstVisibleNote(); -} - -void ClassicTimeline::findLastVisibleNote(const microsec &music_offset) -{ - Iterator note_iterator = _top_note; - while (isVisiblyClose(note_iterator, music_offset)) - { - if (nothingToDraw()) - _first_visible_note = note_iterator; - - auto note = *note_iterator; - - if (!_note_manager->isInGame(note)) - _note_manager->putToGame(note, music_offset); - - ++note_iterator; - } - - _last_visible_note = note_iterator; -} - -void ClassicTimeline::findFirstVisibleNote() -{ - if (nothingToDraw()) - return; - - auto note_iterator = _first_visible_note; - while (note_iterator != _last_visible_note) - { - auto note = *note_iterator; - if (_note_manager->shouldRemove(note)) - ++_first_visible_note; - - ++note_iterator; - } -} - -bool ClassicTimeline::nothingToDraw() const noexcept -{ - return isExpired(_first_visible_note); -} - -void ClassicTimeline::drawVisibleNotes() const -{ - if (nothingToDraw()) - return; - - const auto& note_manager = _note_manager; - std::for_each(_first_visible_note, _last_visible_note, - [¬e_manager](const auto& note) - { - note_manager->draw(note); - }); -} - diff --git a/src/classicgame/classictimeline.h b/src/classicgame/classictimeline.h deleted file mode 100644 index 1cedfce..0000000 --- a/src/classicgame/classictimeline.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "game/timeline.h" - -#include -#include - -class ClassicNote; -class ClassicNoteManager; - -class ClassicTimeline : public Timeline -{ -public: - explicit ClassicTimeline(const std::shared_ptr& manager); - virtual ~ClassicTimeline(); - virtual void update(const microsec& offset) override; - virtual void clear() override; - - virtual void drawVisibleNotes() const override; - - void setNotes(std::vector&& notes, const microsec& visibility); - - void fetchVisibleNotes(); - void findLastVisibleNote(const microsec& music_offset); - void findFirstVisibleNote(); - - using Iterator = std::vector::const_iterator; - - Iterator getActiveNote() noexcept; - - bool isExpired(const Iterator& iterator) const; - inline void expire(Iterator& iterator); - -private: - std::shared_ptr _note_manager; - std::vector _input_intervals; - std::vector _timeline; - microsec _visibility_offset; - microsec _current_offset; - - void updateVisibleSprites(const microsec& music_offset); - void checkCurrentActiveNote(); - void checkForNextActiveNote(); - bool isVisiblyClose(const Iterator& iterator, const microsec& music_offset) const; - inline bool nothingToDraw() const noexcept; - - /* Difference between top and active note is that - * top note is the note handling input right now - * OR it's the closest note from current music offset - * position, not necessarily active. A note stops being top only - * after dying or being tapped by player, even if it's already - * past her perfect offset. - * - * Meanwhile active note is the note which is currently handling - * player input for grade. - * - * An active note is always top note but a top note - * is not always active note. - * */ - - Iterator _top_note; - Iterator _active_note; - Iterator _last_visible_note; - Iterator _first_visible_note; -}; diff --git a/src/main.cpp b/src/main.cpp index bca58bf..07d5556 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#include "application.h" +#include "application/application.h" int main() { diff --git a/src/tools/musicsfml.h b/src/tools/musicsfml.h deleted file mode 100644 index 467a113..0000000 --- a/src/tools/musicsfml.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "tools/music.h" - -#include - -class MusicSFML : public Music -{ -public: - explicit MusicSFML(); - - virtual bool openFromFile(const std::string& filepath) override; - - virtual void play() override; - virtual void pause() override; - virtual void stop() override; - - virtual void setVolume(int volume) override; - - virtual void setOffset(const microsec& offset) override; - virtual microsec fetchOffset() override; - -private: - sf::Music _music; - sf::Clock _offset_interpolator; - - microsec _sfml_music_offset; - microsec _previous_frame_offset; - microsec _absolute_offset; -}; diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000..849dd93 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.8.8) + +project(tools) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +include_directories(${CMAKE_SOURCE_DIR}/include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared) + +file(GLOB_RECURSE HEADERS "shared/*.h" "include/*.h") +file(GLOB_RECURSE SOURCES "src/*.cpp") + +add_library(tools STATIC ${SOURCES} ${HEADERS}) diff --git a/include/tools/beatutils.h b/tools/shared/tools/beatutils.h similarity index 88% rename from include/tools/beatutils.h rename to tools/shared/tools/beatutils.h index 32018f8..f8c03d1 100644 --- a/include/tools/beatutils.h +++ b/tools/shared/tools/beatutils.h @@ -1,7 +1,7 @@ #pragma once #include -#include "mathutils.h" +#include "tools/mathutils.h" namespace beat_utils { diff --git a/include/tools/bpmcalculator.h b/tools/shared/tools/bpmcalculator.h similarity index 100% rename from include/tools/bpmcalculator.h rename to tools/shared/tools/bpmcalculator.h diff --git a/include/tools/mathutils.h b/tools/shared/tools/mathutils.h similarity index 89% rename from include/tools/mathutils.h rename to tools/shared/tools/mathutils.h index cdc12cc..ecffe7e 100644 --- a/include/tools/mathutils.h +++ b/tools/shared/tools/mathutils.h @@ -1,9 +1,6 @@ #pragma once -#include - -using microsec = sf::Int64; -using minute = int; +using microsec = long long; struct Coordinates { diff --git a/tools/shared/tools/music.h b/tools/shared/tools/music.h new file mode 100644 index 0000000..49e5bba --- /dev/null +++ b/tools/shared/tools/music.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include "tools/mathutils.h" + +class Music +{ +public: + explicit Music(); + + bool openFromFile(const std::string& filepath); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + + void setOffset(const microsec& offset); + microsec fetchOffset(); + +private: + sf::Music _music; + sf::Clock _offset_interpolator; + + microsec _sfml_music_offset; + microsec _previous_frame_offset; + microsec _absolute_offset; +}; diff --git a/include/tools/resourceholder.h b/tools/shared/tools/resourceholder.h similarity index 100% rename from include/tools/resourceholder.h rename to tools/shared/tools/resourceholder.h diff --git a/include/settingscontroller.h b/tools/shared/tools/settingscontroller.h similarity index 100% rename from include/settingscontroller.h rename to tools/shared/tools/settingscontroller.h diff --git a/src/tools/beatutils.cpp b/tools/src/beatutils.cpp similarity index 100% rename from src/tools/beatutils.cpp rename to tools/src/beatutils.cpp diff --git a/src/tools/bpmcalculator.cpp b/tools/src/bpmcalculator.cpp similarity index 100% rename from src/tools/bpmcalculator.cpp rename to tools/src/bpmcalculator.cpp diff --git a/src/tools/musicsfml.cpp b/tools/src/music.cpp similarity index 77% rename from src/tools/musicsfml.cpp rename to tools/src/music.cpp index 3d08599..9041369 100644 --- a/src/tools/musicsfml.cpp +++ b/tools/src/music.cpp @@ -1,44 +1,44 @@ -#include "musicsfml.h" +#include "tools/music.h" -MusicSFML::MusicSFML() : +Music::Music() : _sfml_music_offset(0), _previous_frame_offset(0), _absolute_offset(0) {} -bool MusicSFML::openFromFile(const std::string& filepath) +bool Music::openFromFile(const std::string& filepath) { return _music.openFromFile(filepath); } -void MusicSFML::play() +void Music::play() { _music.play(); _sfml_music_offset = _offset_interpolator.restart().asMicroseconds(); } -void MusicSFML::pause() +void Music::pause() { _music.pause(); } -void MusicSFML::stop() +void Music::stop() { _music.stop(); } -void MusicSFML::setVolume(int volume) +void Music::setVolume(int volume) { _music.setVolume(volume); } -void MusicSFML::setOffset(const microsec& offset) +void Music::setOffset(const microsec& offset) { //_previous_frame_offset += (offset - _absolute_offset); _music.setPlayingOffset(sf::microseconds(offset)); } -microsec MusicSFML::fetchOffset() +microsec Music::fetchOffset() { if (_music.getStatus() != sf::Music::Status::Playing) return _absolute_offset;