#include "application.h" #include #include const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f); Application::Application() : _game_window({1280, 720}, "Test"), _debug(true) { _font.loadFromFile("VeraMono.ttf"); _grade.setFont(_font); _grade.setPosition(160, 160); _grade.setFillColor(sf::Color(255, 255, 255, 0)); _grade.setCharacterSize(35); } void Application::run() { // BPM of METEOR is 170. // Length is 1:14 // I calculated that the time between beats is about 1412162 microseconds sf::Int64 iter = 1412162 * 25; while (iter > 0) { Note note(iter, iter + 412162); _timeline.push(note); iter -= 1412162; } // // // // // // // // _music.openFromFile("/home/naiji/METEOR.flac"); _music.play(); _music.setVolume(5); _game_window.display(); startGameLoop(); } static bool isOneFramePassed(const sf::Time& time_since_last_update) { return time_since_last_update >= TIME_PER_FRAME; } void Application::startGameLoop() { sf::Clock timer; sf::Time time_since_last_update = sf::Time::Zero; while (_game_window.isOpen()) { input(); time_since_last_update += timer.restart(); if (isOneFramePassed(time_since_last_update)) { time_since_last_update -= TIME_PER_FRAME; update(); draw(); } } } static sf::Text makeGradeString(const NoteGrade::Rating& rating) { sf::Text ret; switch (rating) { case (NoteGrade::Rating::BAD): ret.setString("BAD"); ret.setFillColor(sf::Color(255, 255, 255, 255)); break; case (NoteGrade::Rating::GREAT): ret.setString("GREAT"); ret.setFillColor(sf::Color(255, 255, 0, 255)); break; case (NoteGrade::Rating::WRONG): ret.setString("WRONG"); ret.setFillColor(sf::Color(120, 120, 120, 255)); break; case (NoteGrade::Rating::GOOD): ret.setString("GOOD"); ret.setFillColor(sf::Color(255, 100, 120, 255)); break; } return ret; } void Application::input() { sf::Event event; while (_game_window.pollEvent(event)) { switch (event.type) { default: break; case (sf::Event::Closed): _game_window.close(); break; case (sf::Event::KeyPressed): onKeyPressed(event.key.code); break; } } } static Note::Arrow keyToArrow(const sf::Keyboard::Key &key) { switch (key) { case sf::Keyboard::A: case sf::Keyboard::Left: case sf::Keyboard::Num4: return Note::Arrow::LEFT; case sf::Keyboard::W: case sf::Keyboard::Up: case sf::Keyboard::Num8: return Note::Arrow::UP; case sf::Keyboard::D: case sf::Keyboard::Right: case sf::Keyboard::Num6: return Note::Arrow::RIGHT; case sf::Keyboard::S: case sf::Keyboard::Down: case sf::Keyboard::Num2: return Note::Arrow::DOWN; default: return Note::Arrow::NONE; } } void Application::onKeyPressed(const sf::Keyboard::Key &key) { if (key == sf::Keyboard::D) { _debug.toggle(); return; } const auto arrow = keyToArrow(key); if (arrow != Note::Arrow::NONE) { _debug.onUserTap(); if (!_timeline.empty()) { const auto current_note = _timeline.top(); const auto grade_result = current_note.onTap(arrow, _music.getPlayingOffset().asMicroseconds()); _grade = makeGradeString(grade_result.rating); } } } void Application::update() { const auto microseconds = _music.getPlayingOffset().asMicroseconds(); if (!_timeline.empty() && _timeline.top().offset() <= microseconds) { _debug.onBeat(); } if (!_timeline.empty() && _timeline.top().deathOffset() <= microseconds) { _timeline.pop(); _debug.onDeath(); } _debug.update(microseconds); if (_grade.getFillColor().a > 0) { const auto alpha = _grade.getFillColor().a - 20; _grade.setFillColor(sf::Color(255, 255, 255, alpha < 0 ? 0 : alpha)); } } void Application::draw() { _game_window.clear(); _debug.drawOn(_game_window); _game_window.draw(_grade); _game_window.display(); }