diff --git a/demo/demo/GameScene.cpp b/demo/demo/GameScene.cpp index 165c4b99fa881fc35509e415d8fde2d99615efde..1bb95b57c96dcfe6eb903038ba5bb334ce32e08a 100644 --- a/demo/demo/GameScene.cpp +++ b/demo/demo/GameScene.cpp @@ -172,8 +172,8 @@ void GameScene::setup() { } } -void GameScene::update() { - Game::update(); +void GameScene::update(float dt) { + Game::update(dt); process_camera(world(), input()); } diff --git a/demo/demo/grid.cpp b/demo/demo/grid.cpp index 670bbb7082315e6a1dc3799f9aa4790f114e53a7..16cec01e9a5032b3fa3f37d2dd7a4907a948edad 100644 --- a/demo/demo/grid.cpp +++ b/demo/demo/grid.cpp @@ -94,13 +94,15 @@ namespace demo { } } - GridScene::GridScene(fggl::App &app) : GameBase(app), m_tiles(), m_grid(nullptr) { + GridScene::GridScene(fggl::App &app) : GameBase(app), m_tiles(), m_animator(15.0F), m_grid(nullptr) { + m_animator.add([this](){this->tickPlayer();}); } void GridScene::activate() { GameBase::activate(); fggl::debug::log(fggl::debug::Level::info, "GridScene::activate()"); + m_animator.reset(); // fake loading the tileset if ( m_tiles.m_floors.empty() ) { @@ -175,6 +177,20 @@ namespace demo { } } + void GridScene::update(float deltaTime) { + GameBase::update(deltaTime); + m_animator.update(deltaTime); + } + + void GridScene::tickPlayer() { + auto &manager = m_grid->entities(); + auto entities = manager.find<CellPos>(); + for (const auto &entity : entities) { + auto &pos = manager.get<CellPos>(entity); + pos.direction = (pos.direction + 1) % 4; + } + } + //float progress = 0.0f; void GridScene::render(fggl::gfx::Graphics &gfx) { fggl::gfx::Paint paint; diff --git a/demo/demo/rollball.cpp b/demo/demo/rollball.cpp index 3ef9ec5e3f12a7fbd650c178aa45df8b9b1a0b22..75439bb41c6e8ad8b20f2ff76703b08873c2cc90 100644 --- a/demo/demo/rollball.cpp +++ b/demo/demo/rollball.cpp @@ -182,12 +182,10 @@ namespace demo { return force; } - void RollBall::update() { - Game::update(); + void RollBall::update(float deltaTime) { + Game::update(deltaTime); m_phys->step(); - const float deltaTime = 1 / 60.0F; - auto& input = this->input(); if ( state.player != fggl::entity::INVALID ) { diff --git a/demo/demo/topdown.cpp b/demo/demo/topdown.cpp index dfc9609eb9bed49b11734052ad6ef375d6945829..c94ca175535ea312ff90e99919eaa77d6990a8cc 100644 --- a/demo/demo/topdown.cpp +++ b/demo/demo/topdown.cpp @@ -127,8 +127,8 @@ void TopDown::activate() { populate_sample_level(factory, world()); } -void TopDown::update() { - Game::update(); +void TopDown::update(float dt) { + Game::update(dt); process_camera(world(), input()); if ( input().mouse.pressed(fggl::input::MouseButton::LEFT) ) { diff --git a/demo/include/GameScene.h b/demo/include/GameScene.h index 84ab5e6360ddab877cc02503f8806a9c4e2ecd50..96232caa1f4aed53dfbb724a596f1dab23f816e5 100644 --- a/demo/include/GameScene.h +++ b/demo/include/GameScene.h @@ -57,7 +57,7 @@ enum camera_type { cam_free, cam_arcball }; setup(); } - void update() override; + void update(float dt) override; void render(fggl::gfx::Graphics& gfx) override; private: diff --git a/demo/include/grid.hpp b/demo/include/grid.hpp index c0fd98d9f353d90e830b579c580da8756f0a04cf..380e7722a6a3da90e01143cde6fc030535168986 100644 --- a/demo/include/grid.hpp +++ b/demo/include/grid.hpp @@ -22,6 +22,7 @@ #include <memory> #include "fggl/scenes/game.hpp" +#include "fggl/animation/animator.hpp" #include "fggl/entity/gridworld/zone.hpp" namespace demo { @@ -47,12 +48,15 @@ namespace demo { void activate() override; void deactivate() override; - //void update() override; + void update(float dt) override; void render(fggl::gfx::Graphics& gfx) override; private: fggl::entity::grid::TileSet m_tiles; + fggl::animation::FrameAnimator m_animator; std::unique_ptr<DemoGrid> m_grid; + void tickPlayer(); + }; } diff --git a/demo/include/rollball.hpp b/demo/include/rollball.hpp index 1b39f0363e42d9a956682c047bfebd9807cb64e5..fc23e5cb892d1a02e7eb8cbe3e630ff26d19e403 100644 --- a/demo/include/rollball.hpp +++ b/demo/include/rollball.hpp @@ -57,7 +57,7 @@ namespace demo { void activate() override; void deactivate() override; - void update() override; + void update(float dt) override; void render(fggl::gfx::Graphics& gfx) override; private: diff --git a/demo/include/topdown.hpp b/demo/include/topdown.hpp index af4642ff3268f25c2127b22a4ffdd6f48b5d4171..519dc900638af4bb6fbe04c9df25b528ac4199a7 100644 --- a/demo/include/topdown.hpp +++ b/demo/include/topdown.hpp @@ -29,7 +29,7 @@ namespace demo { explicit TopDown(fggl::App& app); void activate() override; - void update() override; + void update(float dt) override; void render(fggl::gfx::Graphics& gfx) override; private: diff --git a/fggl/app.cpp b/fggl/app.cpp index 59684c8432776ee51601b84608a76f09aadfc287..baaf2066cf4488b8c275dcee2c4f63b4adbecbf6 100644 --- a/fggl/app.cpp +++ b/fggl/app.cpp @@ -39,7 +39,13 @@ namespace fggl { state.activate(); } + auto lastTime = glfwGetTime(); + while (m_running) { + auto currTime = glfwGetTime(); + auto delta = currTime - lastTime; + lastTime = currTime; + // trigger a state change if expected if (m_expectedScene != m_states.activeID()) { auto result = m_states.change(m_expectedScene); @@ -55,7 +61,7 @@ namespace fggl { //m_modules->onUpdate(); auto &state = m_states.active(); - state.update(); + state.update((float)delta); // window rendering to frame buffer if (m_window != nullptr) { diff --git a/fggl/scenes/game.cpp b/fggl/scenes/game.cpp index db795a3f148e0ea950413984163181ec2fb28206..14a2139b475e8e14d474e99ea4493eeb45e10be9 100644 --- a/fggl/scenes/game.cpp +++ b/fggl/scenes/game.cpp @@ -28,7 +28,7 @@ namespace fggl::scenes { m_input = app.service<input::Input>(); } - void GameBase::update() { + void GameBase::update(float dt) { // detect the user quitting if (m_input != nullptr) { bool escapePressed = m_input->keyboard.pressed(glfwGetKeyScancode(GLFW_KEY_ESCAPE)); @@ -59,7 +59,7 @@ namespace fggl::scenes { m_world.reset(); } - void Game::update() { + void Game::update(float dt) { assert(m_world && "called game update, but there was no world - was activate called?"); if (m_input != nullptr) { diff --git a/fggl/scenes/menu.cpp b/fggl/scenes/menu.cpp index de6dfc0d6cc8ea1178d194853d9135c4ee457ee6..2c38180e524c84fe6618d87cb55c23423170fd4e 100644 --- a/fggl/scenes/menu.cpp +++ b/fggl/scenes/menu.cpp @@ -26,7 +26,7 @@ namespace fggl::scenes { m_inputs = app.service<input::Input>(); } - void BasicMenu::update() { + void BasicMenu::update(float dt) { if (m_inputs != nullptr) { m_cursorPos.x = m_inputs->mouse.axis(MouseAxis::X); m_cursorPos.y = m_inputs->mouse.axis(MouseAxis::Y); diff --git a/include/fggl/animation/animator.hpp b/include/fggl/animation/animator.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2a5170d5b32eafebbee7a8c7f795a74e3d3ff1c1 --- /dev/null +++ b/include/fggl/animation/animator.hpp @@ -0,0 +1,87 @@ +/* + * This file is part of FGGL. + * + * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with FGGL. + * If not, see <https://www.gnu.org/licenses/>. + */ + +// +// Created by webpigeon on 03/09/22. +// + +#ifndef FGGL_ANIMATION_ANIMATOR_H +#define FGGL_ANIMATION_ANIMATOR_H + +#include <functional> +#include <map> +#include <cstdint> +#include <cassert> + +namespace fggl::animation { + + using AnimationCallback = std::function<void(void)>; + using CallbackHandle = uint32_t; + + /** + * Frame-based animation. + * + * Tries to maintain a constant framerate for things that care about that. + */ + class FrameAnimator { + public: + explicit inline FrameAnimator(float targetFPS) : m_target( 1.0F / targetFPS) { + assert( 0 <= m_target ); + } + + inline void reset() { + m_current = 0; + } + + inline void update(float dt) { + assert(0 <= dt); + m_current += dt; + while ( m_current >= m_target) { + tick(); + m_current -= m_target; + } + assert(0 <= m_current); + } + + // tick the animation system, should be handled by update + inline void tick() { + for (auto& [k,v] : m_callbacks) { + v(); + } + } + + inline CallbackHandle add(AnimationCallback callback) { + auto myHandle = m_lastCallback++; + m_callbacks[myHandle] = callback; + return myHandle; + } + + inline void remove(CallbackHandle handle) { + auto itr = m_callbacks.find(handle); + if ( itr != m_callbacks.end() ) { + m_callbacks.erase(itr); + } + } + + private: + const float m_target; + float m_current = 0.0F; + + CallbackHandle m_lastCallback = 0; + std::map<CallbackHandle, AnimationCallback> m_callbacks; + }; + +} // namespace fggl::animation + +#endif //FGGL_ANIMATION_ANIMATOR_H diff --git a/include/fggl/app.hpp b/include/fggl/app.hpp index 13019167c54e170cead9995396eed5a6a814da31..98eab804e7aa6b84f2ecb45d882684ab1673339c 100644 --- a/include/fggl/app.hpp +++ b/include/fggl/app.hpp @@ -58,7 +58,7 @@ namespace fggl { * multiple updates per render or vice-versa depending on requriements. Update is intended for * dispatching game-system related infomation. */ - virtual void update() = 0; + virtual void update(float dt) = 0; /** * Perform actions neccerary for rendering the scene. diff --git a/include/fggl/scenes/game.hpp b/include/fggl/scenes/game.hpp index d9f7155f2db4d60557084557835fc03bd9aa616a..71a129f32115f9b188c011e5d4402afbf13064e9 100644 --- a/include/fggl/scenes/game.hpp +++ b/include/fggl/scenes/game.hpp @@ -30,7 +30,7 @@ namespace fggl::scenes { public: explicit GameBase(fggl::App &app); - void update() override; + void update(float dt) override; void render(fggl::gfx::Graphics &gfx) override = 0; protected: @@ -52,7 +52,7 @@ namespace fggl::scenes { void activate() override; void deactivate() override; - void update() override; + void update(float dt) override; void render(fggl::gfx::Graphics &gfx) override; protected: diff --git a/include/fggl/scenes/menu.hpp b/include/fggl/scenes/menu.hpp index 5c6220c5aab446f352e7153ff7edf12b0ec97714..70c0b15e29d16a0e01087cfcd5d62907313dbb13 100644 --- a/include/fggl/scenes/menu.hpp +++ b/include/fggl/scenes/menu.hpp @@ -32,7 +32,7 @@ namespace fggl::scenes { public: explicit BasicMenu(App &owner); - void update() override; + void update(float dt) override; void render(gfx::Graphics &paint) override; void activate() override;