#include "application.h" #include "note.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() { std::string song_filename = "/home/naiji/METEOR.flac"; _music.openFromFile(song_filename); _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) { // TODO: SHIT BLOCK. _debug.spawnGreenPulse(); const auto note = _timeline.getActiveNote(); if (note) { // This is obscure. Active note on timeline gets received by last ::update() call. // there can be 100-200 microseconds delay between onKeyPressed and update... // Also the problem is that we get music offset by CURRENT music time, // when active note is activated by music time of last ::update call // anyway gotta think on it, smh smh smh const auto music_offset = _music.getPlayingOffset().asMicroseconds(); const auto tap_result = note->onTap(arrow, music_offset); _grade = makeGradeString(tap_result.rating); } } } void Application::update() { const auto music_offset = _music.getPlayingOffset().asMicroseconds(); _timeline.update(music_offset); _debug.update(music_offset); if (_grade.getFillColor().a > 0) // TODO: Encapsulate { const auto alpha = _grade.getFillColor().a - 20; _grade.setFillColor(sf::Color(255, 255, 255, alpha < 0 ? 0 : alpha)); } } void Application::draw() { _game_window.clear(); _game_window.draw(_debug); _game_window.draw(_grade); _game_window.display(); }