Globally redesign CMake and project structure
This commit is contained in:
parent
3388aac813
commit
8d931f7a1e
|
@ -1,77 +1,7 @@
|
||||||
# This file is used to ignore files which are generated
|
# This file is used to ignore files which are generated
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
build
|
||||||
SFML*
|
SFML*
|
||||||
CMake*
|
*.user
|
||||||
|
|
||||||
*~
|
|
||||||
*.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
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wpedantic -g")
|
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_THREAD_LIBS_INIT "-lpthread")
|
||||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||||
set(CMAKE_HAVE_THREADS_LIBRARY 1)
|
set(CMAKE_HAVE_THREADS_LIBRARY 1)
|
||||||
|
@ -13,7 +16,7 @@ set(CMAKE_THREAD_LIBS_INIT "-lpthread")
|
||||||
set(CMAKE_USE_PTHREADS_INIT 1)
|
set(CMAKE_USE_PTHREADS_INIT 1)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
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})
|
add_executable(project-kyoku ${SOURCES})
|
||||||
|
|
||||||
option(SFML_BUILT "SFML_BUILT" ON)
|
option(SFML_BUILT "SFML_BUILT" ON)
|
||||||
|
@ -32,3 +35,20 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(${SFML_INCL_DIR} ${CMAKE_SOURCE_DIR}/include)
|
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()
|
||||||
|
|
|
@ -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)
|
|
@ -1,8 +1,7 @@
|
||||||
#ifndef GAME_H
|
#ifndef GAME_H
|
||||||
#define GAME_H
|
#define GAME_H
|
||||||
|
|
||||||
#include <SFML/Graphics/RenderWindow.hpp>
|
#include "core/inputtype.h"
|
||||||
#include "game/inputtype.h"
|
|
||||||
|
|
||||||
class Game
|
class Game
|
||||||
{
|
{
|
|
@ -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;
|
||||||
|
};
|
|
@ -2,6 +2,7 @@
|
||||||
#define PRECISIONEVALUATOR_H
|
#define PRECISIONEVALUATOR_H
|
||||||
|
|
||||||
#include "tools/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
|
@ -0,0 +1,188 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "tools/mathutils.h"
|
||||||
|
#include "core/note.h"
|
||||||
|
|
||||||
|
template <class TNote, class = std::enable_if_t<std::is_base_of<Note, TNote>::value>>
|
||||||
|
class Timeline
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Timeline() :
|
||||||
|
_current_offset(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
typedef typename std::vector<TNote*>::const_iterator Iterator;
|
||||||
|
|
||||||
|
void setNotes(const std::vector<TNote*>& 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<microsec> _input_intervals;
|
||||||
|
std::vector<TNote*> _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;
|
||||||
|
};
|
|
@ -1,22 +0,0 @@
|
||||||
#ifndef TIMELINE_H
|
|
||||||
#define TIMELINE_H
|
|
||||||
|
|
||||||
#include "tools/mathutils.h"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,21 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tools/mathutils.h"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
|
@ -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)
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "shared/classicmode/classicfactory.h"
|
||||||
|
#include "game/classicgame.h"
|
||||||
|
#include "game/classicgraphicsmanager.h"
|
||||||
|
#include "tools/music.h"
|
||||||
|
|
||||||
|
#include <SFML/Graphics/RenderWindow.hpp>
|
||||||
|
|
||||||
|
std::unique_ptr<Game> classic::init(sf::RenderWindow& game_window)
|
||||||
|
{
|
||||||
|
return std::make_unique<ClassicGame>(std::make_unique<ClassicGraphicsManager>(game_window), std::make_unique<Music>());
|
||||||
|
}
|
|
@ -1,15 +1,10 @@
|
||||||
#include "classicgame.h"
|
#include "classicgame.h"
|
||||||
#include "classictimeline.h"
|
|
||||||
#include "classicnote.h"
|
#include "classicnote.h"
|
||||||
#include "classicmapcreator.h"
|
#include "classicmapcreator.h"
|
||||||
#include "classicnotemanager.h"
|
|
||||||
#include "tools/music.h"
|
#include "tools/music.h"
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
ClassicGame::ClassicGame(std::shared_ptr<ClassicGraphicsManager>&& manager, std::unique_ptr<Music>&& music) :
|
ClassicGame::ClassicGame(std::shared_ptr<ClassicGraphicsManager>&& manager, std::unique_ptr<Music>&& music) :
|
||||||
_graphics_manager(std::move(manager)),
|
_graphics_manager(std::move(manager)),
|
||||||
_note_manager(std::make_unique<ClassicNoteManager>(_graphics_manager)),
|
|
||||||
_timeline(std::make_unique<ClassicTimeline>(_note_manager)),
|
|
||||||
_music(std::move(music)),
|
_music(std::move(music)),
|
||||||
_is_paused(false)
|
_is_paused(false)
|
||||||
{
|
{
|
||||||
|
@ -66,7 +61,7 @@ void ClassicGame::run()
|
||||||
_music->openFromFile("METEOR.flac");
|
_music->openFromFile("METEOR.flac");
|
||||||
_music->setVolume(10);
|
_music->setVolume(10);
|
||||||
_music->play();
|
_music->play();
|
||||||
_timeline->setNotes(std::move(beatmap.notes), beatmap.visibility_offset);
|
_timeline.setNotes(beatmap.notes, beatmap.visibility_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicGame::input(PlayerInput&& inputdata)
|
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);
|
auto note = (*note_it);
|
||||||
_note_manager->input(note, std::move(inputdata));
|
note->input(std::move(inputdata));
|
||||||
_slap.play();
|
_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);
|
_notes_on_hold.emplace_back(note);
|
||||||
std::cout << "HOLD initited by " << inputdata.event.key.code << '\n';
|
std::cout << "HOLD initited by " << inputdata.event.key.code << '\n';
|
||||||
|
@ -116,11 +111,10 @@ void ClassicGame::input(PlayerInput&& inputdata)
|
||||||
|
|
||||||
case sf::Event::KeyReleased:
|
case sf::Event::KeyReleased:
|
||||||
{
|
{
|
||||||
const auto& note_manager = _note_manager;
|
|
||||||
bool key_match = std::any_of(_notes_on_hold.begin(), _notes_on_hold.end(),
|
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)
|
if (key_match)
|
||||||
|
@ -136,11 +130,11 @@ void ClassicGame::input(PlayerInput&& inputdata)
|
||||||
|
|
||||||
void ClassicGame::update()
|
void ClassicGame::update()
|
||||||
{
|
{
|
||||||
_timeline->update(_music->fetchOffset());
|
_timeline.update(_music->fetchOffset());
|
||||||
_timeline->fetchVisibleNotes();
|
_timeline.fetchVisibleNotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassicGame::draw() const
|
void ClassicGame::draw() const
|
||||||
{
|
{
|
||||||
_timeline->drawVisibleNotes();
|
_timeline.drawVisibleNotes();
|
||||||
}
|
}
|
|
@ -3,16 +3,18 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "game/game.h"
|
|
||||||
#include "classicactions.h"
|
|
||||||
#include <SFML/Audio/SoundBuffer.hpp>
|
#include <SFML/Audio/SoundBuffer.hpp>
|
||||||
#include <SFML/Audio/Sound.hpp>
|
#include <SFML/Audio/Sound.hpp>
|
||||||
|
|
||||||
|
#include "core/game.h"
|
||||||
|
#include "core/timeline.h"
|
||||||
|
|
||||||
|
#include "classicnote.h"
|
||||||
|
#include "classicactions.h"
|
||||||
|
|
||||||
class Music;
|
class Music;
|
||||||
class ClassicNote;
|
|
||||||
class ClassicTimeline;
|
|
||||||
class ClassicGraphicsManager;
|
class ClassicGraphicsManager;
|
||||||
class ClassicNoteManager;
|
|
||||||
|
|
||||||
class ClassicGame final : public Game
|
class ClassicGame final : public Game
|
||||||
{
|
{
|
||||||
|
@ -34,8 +36,7 @@ private:
|
||||||
std::vector<ClassicNote*> _notes_on_hold;
|
std::vector<ClassicNote*> _notes_on_hold;
|
||||||
|
|
||||||
std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
|
std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
|
||||||
std::shared_ptr<ClassicNoteManager> _note_manager;
|
Timeline<ClassicNote> _timeline;
|
||||||
std::unique_ptr<ClassicTimeline> _timeline;
|
|
||||||
|
|
||||||
sf::SoundBuffer _slap_buffer;
|
sf::SoundBuffer _slap_buffer;
|
||||||
sf::Sound _slap;
|
sf::Sound _slap;
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "game/spritecontainer.h"
|
#include "spritecontainer.h"
|
||||||
#include "classicactions.h"
|
#include "classicactions.h"
|
||||||
#include "classicspritefactory.h"
|
#include "classicspritefactory.h"
|
||||||
|
|
|
@ -35,43 +35,29 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const
|
||||||
|
|
||||||
while (bpm_iterator < bpm_end)
|
while (bpm_iterator < bpm_end)
|
||||||
{
|
{
|
||||||
ClassicNote *note = new ClassicNote(
|
ClassicNote::ClassicNoteInitializer init;
|
||||||
{
|
ClassicNote::ClassicNoteInitializer::Element element;
|
||||||
{input_intervals, bpm_iterator},
|
init.intervals = input_intervals;
|
||||||
{input_intervals},
|
init.perfect_offset = bpm_iterator;
|
||||||
false,
|
init.hold = 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;
|
element.coordinates = {x, 390.};
|
||||||
note->elements[0].animations[ClassicNoteState::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>();
|
element.falling_curve_interpolation = {};
|
||||||
note->elements[0].animations[ClassicNoteState::ACTIVE] = note->elements[0].animations[ClassicNoteState::FLYING];
|
element.keys = {sf::Keyboard::W, sf::Keyboard::Up};
|
||||||
note->elements[0].animations[ClassicNoteState::DYING] = std::make_shared<ClassicDyingAnimationScenario>();
|
element.type = Type::UP;
|
||||||
note->elements[0].animations[ClassicNoteState::DEAD] = nullptr;
|
|
||||||
|
|
||||||
if (counter == 0)
|
if (counter == 0)
|
||||||
{
|
{
|
||||||
note->hold = true;
|
init.hold = true;
|
||||||
note->elements[0].available_keys = {sf::Keyboard::D, sf::Keyboard::Right};
|
element.keys = {sf::Keyboard::D, sf::Keyboard::Right};
|
||||||
note->elements[0].type = Type::RIGHT;
|
element.type = Type::RIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
--counter;
|
--counter;
|
||||||
|
|
||||||
notes.emplace_back(note);
|
init.elements = {element};
|
||||||
|
|
||||||
|
notes.emplace_back(new ClassicNote(std::move(init), _graphics_manager));
|
||||||
|
|
||||||
bpm_iterator += tempo_interval;
|
bpm_iterator += tempo_interval;
|
||||||
x += 70;
|
x += 70;
|
||||||
|
@ -82,3 +68,4 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const
|
||||||
|
|
||||||
return {std::move(notes), note_input_offset * 12};
|
return {std::move(notes), note_input_offset * 12};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "tools/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
|
#include "core/note.h"
|
||||||
|
|
||||||
#include "classicgraphicsmanager.h"
|
#include "classicgraphicsmanager.h"
|
||||||
|
|
||||||
struct Beatmap
|
struct Beatmap
|
|
@ -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<ClassicGraphicsManager>& 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<ClassicFlyingAnimationScenario>();
|
||||||
|
_elements[i].animations[State::ACTIVE] = _elements[i].animations[State::FLYING];
|
||||||
|
_elements[i].animations[State::DYING] = std::make_shared<ClassicDyingAnimationScenario>();
|
||||||
|
_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<int>(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;
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/note.h"
|
||||||
|
#include "core/precisionevaluator.h"
|
||||||
|
#include "classicactions.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
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<microsec> intervals;
|
||||||
|
microsec perfect_offset;
|
||||||
|
bool hold;
|
||||||
|
|
||||||
|
struct Element
|
||||||
|
{
|
||||||
|
Type type;
|
||||||
|
Coordinates coordinates;
|
||||||
|
std::vector<Coordinates> falling_curve_interpolation;
|
||||||
|
std::array<sf::Keyboard::Key, 2> keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Element> elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit ClassicNote(ClassicNoteInitializer&& init, const std::shared_ptr<ClassicGraphicsManager>& 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<ClassicSprite> sprite;
|
||||||
|
std::array<std::shared_ptr<ClassicAnimationScenario>, 5> animations;
|
||||||
|
|
||||||
|
std::array<sf::Keyboard::Key, 2> 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<NoteElement> _elements;
|
||||||
|
|
||||||
|
const PrecisionEvaluator<Grade> _evaluator;
|
||||||
|
const std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
|
||||||
|
|
||||||
|
State _state;
|
||||||
|
bool _isHold;
|
||||||
|
};
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "tools/mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
#include "game/sprite.h"
|
#include "sprite.h"
|
||||||
#include "SFML/Graphics/RectangleShape.hpp"
|
#include <SFML/Graphics/RectangleShape.hpp>
|
||||||
#include "SFML/Graphics/Text.hpp"
|
#include <SFML/Graphics/Text.hpp>
|
||||||
|
|
||||||
class ClassicSprite : public Sprite, public sf::Drawable
|
class ClassicSprite : public Sprite, public sf::Drawable
|
||||||
{
|
{
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class Game;
|
||||||
|
|
||||||
|
namespace sf { class RenderWindow; }
|
||||||
|
|
||||||
|
namespace classic
|
||||||
|
{
|
||||||
|
std::unique_ptr<Game> init(sf::RenderWindow &game_window);
|
||||||
|
}
|
|
@ -1,14 +1,12 @@
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "game/inputtype.h"
|
#include "core/inputtype.h"
|
||||||
|
|
||||||
#include "classicgame/classicgame.h"
|
#include "mainmenu.h"
|
||||||
#include "classicgame/classicgraphicsmanager.h"
|
#include "gamestate.h"
|
||||||
|
#include "editor.h"
|
||||||
|
|
||||||
#include "gui/mainmenu.h"
|
#include "tools/music.h"
|
||||||
#include "gui/gamestate.h"
|
#include "classicmode/classicfactory.h"
|
||||||
#include "gui/editor.h"
|
|
||||||
|
|
||||||
#include "tools/musicsfml.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
@ -19,7 +17,7 @@ Application::Application() :
|
||||||
{
|
{
|
||||||
_font_holder.load(Fonts::Id::GUI, "SourceCodePro-Regular.ttf");
|
_font_holder.load(Fonts::Id::GUI, "SourceCodePro-Regular.ttf");
|
||||||
|
|
||||||
_game = std::make_unique<ClassicGame>(std::make_unique<ClassicGraphicsManager>(_game_window), std::make_unique<MusicSFML>());
|
_game = classic::init(_game_window);
|
||||||
|
|
||||||
_game_window.setFramerateLimit(60);
|
_game_window.setFramerateLimit(60);
|
||||||
_game_window.setKeyRepeatEnabled(false);
|
_game_window.setKeyRepeatEnabled(false);
|
||||||
|
@ -36,7 +34,7 @@ Application::Application() :
|
||||||
|
|
||||||
const auto main_menu = std::make_shared<MainMenu>(_game_window, std::move(callbacks), _font_holder);
|
const auto main_menu = std::make_shared<MainMenu>(_game_window, std::move(callbacks), _font_holder);
|
||||||
const auto game_state = std::make_shared<GameState>(_game_window, _game, GameState::Callbacks());
|
const auto game_state = std::make_shared<GameState>(_game_window, _game, GameState::Callbacks());
|
||||||
const auto editor = std::make_shared<Editor>(_game_window, std::move(editor_callbacks), std::make_unique<MusicSFML>(), _font_holder);
|
const auto editor = std::make_shared<Editor>(_game_window, std::move(editor_callbacks), std::make_unique<Music>(), _font_holder);
|
||||||
|
|
||||||
_states[GUIState::Tag::MAIN_MENU] = main_menu;
|
_states[GUIState::Tag::MAIN_MENU] = main_menu;
|
||||||
_states[GUIState::Tag::GAME] = game_state;
|
_states[GUIState::Tag::GAME] = game_state;
|
|
@ -1,14 +1,18 @@
|
||||||
#ifndef APPLICATION_H
|
#ifndef APPLICATION_H
|
||||||
#define APPLICATION_H
|
#define APPLICATION_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
#include <SFML/Graphics/RenderWindow.hpp>
|
||||||
|
#include <SFML/Graphics/Font.hpp>
|
||||||
#include <SFML/System/Clock.hpp>
|
#include <SFML/System/Clock.hpp>
|
||||||
#include <SFML/Window/Keyboard.hpp>
|
#include <SFML/Window/Keyboard.hpp>
|
||||||
#include <SFML/Window/Event.hpp>
|
#include <SFML/Window/Event.hpp>
|
||||||
|
|
||||||
#include "game/game.h"
|
#include "core/game.h"
|
||||||
#include "gui/state.h"
|
#include "state.h"
|
||||||
|
|
||||||
#include "tools/resourceholder.h"
|
#include "tools/resourceholder.h"
|
||||||
|
|
||||||
|
@ -25,7 +29,6 @@ private:
|
||||||
std::array<std::shared_ptr<GUIState>, GUIState::Tag::AMOUNT> _states;
|
std::array<std::shared_ptr<GUIState>, GUIState::Tag::AMOUNT> _states;
|
||||||
std::vector<std::shared_ptr<GUIState>> _state_stack;
|
std::vector<std::shared_ptr<GUIState>> _state_stack;
|
||||||
|
|
||||||
|
|
||||||
sf::RenderWindow _game_window;
|
sf::RenderWindow _game_window;
|
||||||
std::shared_ptr<Game> _game;
|
std::shared_ptr<Game> _game;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gui/state.h"
|
#include "state.h"
|
||||||
#include "tools/music.h"
|
#include "tools/music.h"
|
||||||
#include "tools/resourceholder.h"
|
#include "tools/resourceholder.h"
|
||||||
#include <SFML/Graphics/RenderWindow.hpp>
|
#include <SFML/Graphics/RenderWindow.hpp>
|
|
@ -2,7 +2,7 @@
|
||||||
#include "widgets/button.h"
|
#include "widgets/button.h"
|
||||||
#include "widgets/group.h"
|
#include "widgets/group.h"
|
||||||
|
|
||||||
#include "game/game.h"
|
#include "core/game.h"
|
||||||
|
|
||||||
GameState::GameState(sf::RenderWindow& game_window, const std::shared_ptr<Game>& game,
|
GameState::GameState(sf::RenderWindow& game_window, const std::shared_ptr<Game>& game,
|
||||||
Callbacks&& callbacks) :
|
Callbacks&& callbacks) :
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gui/state.h"
|
#include "state.h"
|
||||||
#include <SFML/Graphics/RenderWindow.hpp>
|
#include <SFML/Graphics/RenderWindow.hpp>
|
||||||
|
|
||||||
class Group;
|
class Group;
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "gui/state.h"
|
#include "state.h"
|
||||||
#include "tools/resourceholder.h"
|
#include "tools/resourceholder.h"
|
||||||
#include <SFML/Graphics/RenderWindow.hpp>
|
#include <SFML/Graphics/RenderWindow.hpp>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
Button::Button(const std::string &text, const std::shared_ptr<sf::Font>& font, unsigned int font_size) :
|
Button::Button(const std::string &text, const std::shared_ptr<sf::Font>& font, unsigned int font_size) :
|
||||||
_font(font)
|
_font(font)
|
||||||
{
|
{
|
|
@ -1,56 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "classicactions.h"
|
|
||||||
#include "game/precisionevaluator.h"
|
|
||||||
|
|
||||||
#include "SFML/Window/Keyboard.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
enum class ClassicGrade
|
|
||||||
{
|
|
||||||
PERFECT,
|
|
||||||
GOOD,
|
|
||||||
BAD
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ClassicNoteState
|
|
||||||
{
|
|
||||||
NONE,
|
|
||||||
|
|
||||||
FLYING,
|
|
||||||
ACTIVE,
|
|
||||||
DYING,
|
|
||||||
DEAD
|
|
||||||
};
|
|
||||||
|
|
||||||
class ClassicSprite;
|
|
||||||
class ClassicAnimationScenario;
|
|
||||||
|
|
||||||
struct ClassicNote
|
|
||||||
{
|
|
||||||
PrecisionEvaluator<ClassicGrade> evaluator;
|
|
||||||
std::vector<microsec> 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<Coordinates> falling_curve_interpolation;
|
|
||||||
std::array<sf::Keyboard::Key, 2> available_keys;
|
|
||||||
std::shared_ptr<ClassicSprite> sprite;
|
|
||||||
std::array<std::shared_ptr<ClassicAnimationScenario>, 5> animations;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Element> elements;
|
|
||||||
};
|
|
|
@ -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<ClassicGraphicsManager>& 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<int>(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;
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "game/inputtype.h"
|
|
||||||
#include "classicnote.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class ClassicGraphicsManager;
|
|
||||||
|
|
||||||
class ClassicNoteManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit ClassicNoteManager(const std::shared_ptr<ClassicGraphicsManager>& 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<ClassicGraphicsManager> _graphics_manager;
|
|
||||||
};
|
|
|
@ -1,160 +0,0 @@
|
||||||
#include "classictimeline.h"
|
|
||||||
#include "classicnotemanager.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
ClassicTimeline::ClassicTimeline(const std::shared_ptr<ClassicNoteManager>& manager) :
|
|
||||||
_note_manager(manager),
|
|
||||||
_current_offset(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void ClassicTimeline::setNotes(std::vector<ClassicNote *> &¬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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "game/timeline.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class ClassicNote;
|
|
||||||
class ClassicNoteManager;
|
|
||||||
|
|
||||||
class ClassicTimeline : public Timeline
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit ClassicTimeline(const std::shared_ptr<ClassicNoteManager>& manager);
|
|
||||||
virtual ~ClassicTimeline();
|
|
||||||
virtual void update(const microsec& offset) override;
|
|
||||||
virtual void clear() override;
|
|
||||||
|
|
||||||
virtual void drawVisibleNotes() const override;
|
|
||||||
|
|
||||||
void setNotes(std::vector<ClassicNote*>&& notes, const microsec& visibility);
|
|
||||||
|
|
||||||
void fetchVisibleNotes();
|
|
||||||
void findLastVisibleNote(const microsec& music_offset);
|
|
||||||
void findFirstVisibleNote();
|
|
||||||
|
|
||||||
using Iterator = std::vector<ClassicNote*>::const_iterator;
|
|
||||||
|
|
||||||
Iterator getActiveNote() noexcept;
|
|
||||||
|
|
||||||
bool isExpired(const Iterator& iterator) const;
|
|
||||||
inline void expire(Iterator& iterator);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<ClassicNoteManager> _note_manager;
|
|
||||||
std::vector<microsec> _input_intervals;
|
|
||||||
std::vector<ClassicNote*> _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;
|
|
||||||
};
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "application.h"
|
#include "application/application.h"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "tools/music.h"
|
|
||||||
|
|
||||||
#include <SFML/Audio/Music.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
|
@ -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})
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "mathutils.h"
|
#include "tools/mathutils.h"
|
||||||
|
|
||||||
namespace beat_utils
|
namespace beat_utils
|
||||||
{
|
{
|
|
@ -1,9 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SFML/System/Clock.hpp>
|
using microsec = long long;
|
||||||
|
|
||||||
using microsec = sf::Int64;
|
|
||||||
using minute = int;
|
|
||||||
|
|
||||||
struct Coordinates
|
struct Coordinates
|
||||||
{
|
{
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SFML/Audio/Music.hpp>
|
||||||
|
#include <SFML/System/Clock.hpp>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
|
@ -1,44 +1,44 @@
|
||||||
#include "musicsfml.h"
|
#include "tools/music.h"
|
||||||
|
|
||||||
MusicSFML::MusicSFML() :
|
Music::Music() :
|
||||||
_sfml_music_offset(0),
|
_sfml_music_offset(0),
|
||||||
_previous_frame_offset(0),
|
_previous_frame_offset(0),
|
||||||
_absolute_offset(0)
|
_absolute_offset(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool MusicSFML::openFromFile(const std::string& filepath)
|
bool Music::openFromFile(const std::string& filepath)
|
||||||
{
|
{
|
||||||
return _music.openFromFile(filepath);
|
return _music.openFromFile(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSFML::play()
|
void Music::play()
|
||||||
{
|
{
|
||||||
_music.play();
|
_music.play();
|
||||||
_sfml_music_offset = _offset_interpolator.restart().asMicroseconds();
|
_sfml_music_offset = _offset_interpolator.restart().asMicroseconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSFML::pause()
|
void Music::pause()
|
||||||
{
|
{
|
||||||
_music.pause();
|
_music.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSFML::stop()
|
void Music::stop()
|
||||||
{
|
{
|
||||||
_music.stop();
|
_music.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSFML::setVolume(int volume)
|
void Music::setVolume(int volume)
|
||||||
{
|
{
|
||||||
_music.setVolume(volume);
|
_music.setVolume(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MusicSFML::setOffset(const microsec& offset)
|
void Music::setOffset(const microsec& offset)
|
||||||
{
|
{
|
||||||
//_previous_frame_offset += (offset - _absolute_offset);
|
//_previous_frame_offset += (offset - _absolute_offset);
|
||||||
_music.setPlayingOffset(sf::microseconds(offset));
|
_music.setPlayingOffset(sf::microseconds(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
microsec MusicSFML::fetchOffset()
|
microsec Music::fetchOffset()
|
||||||
{
|
{
|
||||||
if (_music.getStatus() != sf::Music::Status::Playing)
|
if (_music.getStatus() != sf::Music::Status::Playing)
|
||||||
return _absolute_offset;
|
return _absolute_offset;
|
Loading…
Reference in New Issue