Kale
Loading...
Searching...
No Matches
StateAnimatable.hpp
Go to the documentation of this file.
1/*
2 Copyright 2022 Rishi Challa
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 http://www.apache.org/licenses/LICENSE-2.0
7 Unless required by applicable law or agreed to in writing, software
8 distributed under the License is distributed on an "AS IS" BASIS,
9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 See the License for the specific language governing permissions and
11 limitations under the License.
12*/
13
14#pragma once
15
18
19#include <unordered_map>
20#include <vector>
21#include <utility>
22#include <mutex>
23#include <memory>
24
25#include <nlohmann/json.hpp>
26
27namespace Kale {
28
33 using JSON = nlohmann::json;
34
39 template <typename S> class StateAnimatable {
40 protected:
41
45 int state;
46
51
56
61
66
70 std::unordered_map<int, S> structures;
71
75 std::vector<std::pair<int, float>> animationInfo;
76
81
86
87 public:
88
93
99 // Loop through the structures & set them
100 for (const std::pair<std::string, S>& pair : json["structures"].get<std::unordered_map<std::string, S>>())
101 structures[std::stoi(pair.first)] = pair.second;
102
103 // Set the first state if applicable
104 if (json.contains("state")) setState<int>(json["state"].get<int>());
105
106 // Start animating if applicable
107 if (json.contains("animation")) {
108 // Get the animation subset of the json
109 JSON animationInfo = json["animation"];
110
111 // Get the type of animation and convert it to lowercase (loop or once)
112 std::string type = animationInfo["type"].get<std::string>();
113 std::transform(type.begin(), type.end(), type.begin(), [](char c) -> char { return std::tolower(c); });
114
115 // Get the stages data
116 std::vector<std::pair<int, float>> stages;
117 std::vector<JSON> stagesJson = animationInfo["stages"].get<std::vector<JSON>>();
118 for (const JSON& json : stagesJson) stages.push_back(std::make_pair(json["state"].get<int>(), json["duration"].get<float>()));
119
120 // Animate based on the type
121 if (type == "loop") animateLoop(stages);
122 if (type == "once") animateOnce(stages);
123 }
124 }
125
131 void updateState(float deltaTime) {
132 if (!transitioning) return;
133 transitionTime += deltaTime / (1000000.0f * transitionDuration);
134
135 // Animation complete
136 if (transitionTime >= 1.0f) {
138
139 // There is no further animation required
140 if (animationInfo.empty()) {
141 transitioning = false;
142 return;
143 }
144
145 // We need to move to the next animation stage
146 if (++animationIndex >= animationInfo.size()) {
147 // We don't need to loop, we've finished.
148 if (!animationLoop) {
149 animationInfo.clear();
150 transitioning = false;
151 return;
152 }
153
154 // We finished going through the animation info, check if we need to repeat
155 animationIndex = 0;
156 }
157
158 // Prepare the next animation
159 transitionTime = 0.0f;
162 }
163 }
164
171 template <typename T> void addStructure(T state, const S& structure) {
172 structures[static_cast<int>(state)] = structure;
173 }
174
180 template <typename T> void removeStructure(T state) {
181 structures.erase(static_cast<int>(state));
182 }
183
190 template <typename T> S getStructure(T state) const {
191 return structures.at(static_cast<int>(state));
192 }
193
201 template <typename T> void animateTo(T state, float duration) {
202 animationInfo.clear();
203 transitioning = true;
204 transitionTime = 0.0f;
205 transitionDuration = duration;
206 transitionState = static_cast<int>(state);
207 }
208
214 template <typename T> void animateOnce(std::vector<std::pair<T, float>> stages) {
215 animationInfo.clear();
216 for (const std::pair<T, float> stage : stages)
217 animationInfo.push_back(std::make_pair(static_cast<int>(stage.first), stage.second));
218 animationIndex = 0;
219 animationLoop = false;
220
221 transitioning = true;
222 transitionTime = 0.0f;
223 transitionDuration = stages[0].second;
224 transitionState = static_cast<int>(stages[0].first);
225 }
226
232 template <typename T> void animateLoop(std::vector<std::pair<T, float>> stages) {
233 animationInfo.clear();
234 for (const std::pair<T, float> stage : stages)
235 animationInfo.push_back(std::make_pair(static_cast<int>(stage.first), stage.second));
236 animationIndex = 0;
237 animationLoop = true;
238
239 transitioning = true;
240 transitionTime = 0.0f;
241 transitionDuration = stages[0].second;
242 transitionState = static_cast<int>(stages[0].first);
243 }
244
251 template <typename T> void setState(T state) {
252 animationInfo.clear();
253 transitioning = false;
254 this->state = static_cast<int>(state);
255 }
256
264 template <typename T> T getCurrentState() const {
265 if (!transitioning) return static_cast<T>(state);
266 return transitionTime > 0.5f ? static_cast<T>(transitionState) : static_cast<T>(state);
267 }
268
276 template <typename T> std::vector<std::pair<T, float>> getStateComposition() const {
277 std::vector<std::pair<T, float>> composition;
278 if (!transitioning) {
279 composition.push_back(std::make_pair(static_cast<T>(state), 1.0f));
280 return composition;
281 }
282
283 composition.push_back(std::make_pair(static_cast<T>(state), 1.0f - transitionTime));
284 composition.push_back(std::make_pair(static_cast<T>(transitionState), transitionTime));
285 return composition;
286 }
287
294 bool isTransitioning() const {
295 return transitioning;
296 }
297 };
298}
void animateOnce(std::vector< std::pair< T, float > > stages)
std::vector< std::pair< T, float > > getStateComposition() const
void animateLoop(std::vector< std::pair< T, float > > stages)
void addStructure(T state, const S &structure)
void animateTo(T state, float duration)
std::vector< std::pair< int, float > > animationInfo
std::unordered_map< int, S > structures
S getStructure(T state) const
void updateState(float deltaTime)
nlohmann::json JSON
Definition Scene.hpp:39