From 84728b73c6cb021bb0f2b4e06e8dae03c8816853 Mon Sep 17 00:00:00 2001
From: Joseph Walton-Rivers <joseph@walton-rivers.uk>
Date: Sat, 3 Sep 2022 22:44:26 +0100
Subject: [PATCH] make player spin in grid world

---
 demo/demo/GameScene.cpp             |  4 +-
 demo/demo/grid.cpp                  | 18 +++++-
 demo/demo/rollball.cpp              |  6 +-
 demo/demo/topdown.cpp               |  4 +-
 demo/include/GameScene.h            |  2 +-
 demo/include/grid.hpp               |  6 +-
 demo/include/rollball.hpp           |  2 +-
 demo/include/topdown.hpp            |  2 +-
 fggl/app.cpp                        |  8 ++-
 fggl/scenes/game.cpp                |  4 +-
 fggl/scenes/menu.cpp                |  2 +-
 include/fggl/animation/animator.hpp | 87 +++++++++++++++++++++++++++++
 include/fggl/app.hpp                |  2 +-
 include/fggl/scenes/game.hpp        |  4 +-
 include/fggl/scenes/menu.hpp        |  2 +-
 15 files changed, 132 insertions(+), 21 deletions(-)
 create mode 100644 include/fggl/animation/animator.hpp

diff --git a/demo/demo/GameScene.cpp b/demo/demo/GameScene.cpp
index 165c4b9..1bb95b5 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 670bbb7..16cec01 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 3ef9ec5..75439bb 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 dfc9609..c94ca17 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 84ab5e6..96232ca 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 c0fd98d..380e772 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 1b39f03..fc23e5c 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 af4642f..519dc90 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 59684c8..baaf206 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 db795a3..14a2139 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 de6dfc0..2c38180 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 0000000..2a5170d
--- /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 1301916..98eab80 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 d9f7155..71a129f 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 5c6220c..70c0b15 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;
-- 
GitLab