Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
AnimationGraph.cpp
Go to the documentation of this file.
1/*
2Olympe Engine V2 2025
3Animation System - Animation Graph Implementation
4*/
5
6#include "AnimationGraph.h"
7#include "../json_helper.h"
8#include "../system/system_utils.h"
9#include <algorithm>
10
12
13namespace OlympeAnimation
14{
15 // ========================================================================
16 // AnimationGraph Implementation
17 // ========================================================================
18
19 bool AnimationGraph::LoadFromFile(const std::string& filePath)
20 {
21 json j;
22 if (!JsonHelper::LoadJsonFromFile(filePath, j))
23 {
24 SYSTEM_LOG << "AnimationGraph: Failed to load file: " << filePath << "\n";
25 return false;
26 }
27
28 return ParseJSON(j.dump());
29 }
30
31 bool AnimationGraph::ParseJSON(const std::string& jsonContent)
32 {
33 try
34 {
35 json j = json::parse(jsonContent);
36
37 // Parse basic info
38 m_graphName = JsonHelper::GetString(j, "graphName", "unknown");
39 m_description = JsonHelper::GetString(j, "description", "");
40 m_animationBankPath = JsonHelper::GetString(j, "animationBankPath", "");
41 m_defaultState = JsonHelper::GetString(j, "defaultState", "Idle");
43
44 // Parse parameters
45 if (j.contains("parameters") && j["parameters"].is_array())
46 {
47 for (const auto& paramJson : j["parameters"])
48 {
49 std::string name = JsonHelper::GetString(paramJson, "name", "");
50 std::string typeStr = JsonHelper::GetString(paramJson, "type", "float");
51
52 ParameterValue value;
53 if (typeStr == "bool")
54 {
56 value.boolValue = JsonHelper::GetBool(paramJson, "defaultValue", false);
57 }
58 else if (typeStr == "float")
59 {
61 value.floatValue = JsonHelper::GetFloat(paramJson, "defaultValue", 0.0f);
62 }
63 else if (typeStr == "int")
64 {
66 value.intValue = JsonHelper::GetInt(paramJson, "defaultValue", 0);
67 }
68 else if (typeStr == "string")
69 {
71 value.stringValue = JsonHelper::GetString(paramJson, "defaultValue", "");
72 }
73
74 m_parameters[name] = value;
75 }
76 }
77
78 // Parse states
79 if (j.contains("states") && j["states"].is_array())
80 {
81 for (const auto& stateJson : j["states"])
82 {
83 AnimationState state;
84 state.name = JsonHelper::GetString(stateJson, "name", "");
85 state.animationName = JsonHelper::GetString(stateJson, "animationName", "");
86 state.priority = JsonHelper::GetInt(stateJson, "priority", 0);
87
88 std::string blendModeStr = JsonHelper::GetString(stateJson, "blendMode", "override");
89 if (blendModeStr == "additive")
91 else if (blendModeStr == "blend")
93 else
95
96 m_states[state.name] = state;
97 }
98 }
99
100 // Parse transitions
101 if (j.contains("transitions") && j["transitions"].is_array())
102 {
103 for (const auto& transJson : j["transitions"])
104 {
107 trans.toState = JsonHelper::GetString(transJson, "to", "");
108 trans.transitionTime = JsonHelper::GetFloat(transJson, "transitionTime", 0.1f);
109
110 // Parse conditions
111 if (transJson.contains("conditions") && transJson["conditions"].is_array())
112 {
113 for (const auto& condJson : transJson["conditions"])
114 {
116 cond.parameter = JsonHelper::GetString(condJson, "parameter", "");
117
118 // Parse operator
119 std::string opStr = JsonHelper::GetString(condJson, "operator", "==");
120 if (opStr == "==") cond.op = ComparisonOperator::Equal;
121 else if (opStr == "!=") cond.op = ComparisonOperator::NotEqual;
122 else if (opStr == ">") cond.op = ComparisonOperator::Greater;
123 else if (opStr == ">=") cond.op = ComparisonOperator::GreaterOrEqual;
124 else if (opStr == "<") cond.op = ComparisonOperator::Less;
125 else if (opStr == "<=") cond.op = ComparisonOperator::LessOrEqual;
126
127 // Parse value based on type
128 if (condJson.contains("value"))
129 {
130 if (condJson["value"].is_boolean())
131 {
132 cond.value = ParameterValue(condJson["value"].get<bool>());
133 }
134 else if (condJson["value"].is_number_float())
135 {
136 cond.value = ParameterValue(condJson["value"].get<float>());
137 }
138 else if (condJson["value"].is_number_integer())
139 {
140 cond.value = ParameterValue(condJson["value"].get<int>());
141 }
142 else if (condJson["value"].is_string())
143 {
144 cond.value = ParameterValue(condJson["value"].get<std::string>());
145 }
146 }
147
148 trans.conditions.push_back(cond);
149 }
150 }
151
152 m_transitions.push_back(trans);
153 }
154 }
155
156 m_isValid = true;
157 SYSTEM_LOG << "AnimationGraph: Successfully loaded '" << m_graphName
158 << "' with " << m_states.size() << " states and "
159 << m_transitions.size() << " transitions\n";
160 return true;
161 }
162 catch (const std::exception& e)
163 {
164 SYSTEM_LOG << "AnimationGraph: Error parsing JSON: " << e.what() << "\n";
165 return false;
166 }
167 }
168
169 void AnimationGraph::SetParameter(const std::string& name, bool value)
170 {
171 m_parameters[name] = ParameterValue(value);
172 }
173
174 void AnimationGraph::SetParameter(const std::string& name, float value)
175 {
176 m_parameters[name] = ParameterValue(value);
177 }
178
179 void AnimationGraph::SetParameter(const std::string& name, int value)
180 {
181 m_parameters[name] = ParameterValue(value);
182 }
183
184 void AnimationGraph::SetParameter(const std::string& name, const std::string& value)
185 {
186 m_parameters[name] = ParameterValue(value);
187 }
188
189 bool AnimationGraph::GetParameterBool(const std::string& name, bool defaultValue) const
190 {
191 auto it = m_parameters.find(name);
192 if (it != m_parameters.end() && it->second.type == ParameterType::Bool)
193 return it->second.boolValue;
194 return defaultValue;
195 }
196
197 float AnimationGraph::GetParameterFloat(const std::string& name, float defaultValue) const
198 {
199 auto it = m_parameters.find(name);
200 if (it != m_parameters.end() && it->second.type == ParameterType::Float)
201 return it->second.floatValue;
202 return defaultValue;
203 }
204
205 int AnimationGraph::GetParameterInt(const std::string& name, int defaultValue) const
206 {
207 auto it = m_parameters.find(name);
208 if (it != m_parameters.end() && it->second.type == ParameterType::Int)
209 return it->second.intValue;
210 return defaultValue;
211 }
212
213 std::string AnimationGraph::GetParameterString(const std::string& name, const std::string& defaultValue) const
214 {
215 auto it = m_parameters.find(name);
216 if (it != m_parameters.end() && it->second.type == ParameterType::String)
217 return it->second.stringValue;
218 return defaultValue;
219 }
220
222 {
223 if (m_states.find(stateName) != m_states.end())
224 {
226 }
227 }
228
230 {
231 auto it = m_states.find(m_currentState);
232 if (it != m_states.end())
233 return it->second.animationName;
234 return "";
235 }
236
237 bool AnimationGraph::Update(float deltaTime)
238 {
240 if (validTransition)
241 {
243 return true;
244 }
245 return false;
246 }
247
249 {
250 auto it = m_parameters.find(condition.parameter);
251 if (it == m_parameters.end())
252 return false;
253
254 const ParameterValue& paramValue = it->second;
255 const ParameterValue& condValue = condition.value;
256
257 // Type must match
258 if (paramValue.type != condValue.type)
259 return false;
260
261 switch (paramValue.type)
262 {
265 return paramValue.boolValue == condValue.boolValue;
267 return paramValue.boolValue != condValue.boolValue;
268 break;
269
271 switch (condition.op)
272 {
273 case ComparisonOperator::Equal: return paramValue.floatValue == condValue.floatValue;
274 case ComparisonOperator::NotEqual: return paramValue.floatValue != condValue.floatValue;
275 case ComparisonOperator::Greater: return paramValue.floatValue > condValue.floatValue;
276 case ComparisonOperator::GreaterOrEqual: return paramValue.floatValue >= condValue.floatValue;
277 case ComparisonOperator::Less: return paramValue.floatValue < condValue.floatValue;
278 case ComparisonOperator::LessOrEqual: return paramValue.floatValue <= condValue.floatValue;
279 }
280 break;
281
283 switch (condition.op)
284 {
285 case ComparisonOperator::Equal: return paramValue.intValue == condValue.intValue;
286 case ComparisonOperator::NotEqual: return paramValue.intValue != condValue.intValue;
287 case ComparisonOperator::Greater: return paramValue.intValue > condValue.intValue;
288 case ComparisonOperator::GreaterOrEqual: return paramValue.intValue >= condValue.intValue;
289 case ComparisonOperator::Less: return paramValue.intValue < condValue.intValue;
290 case ComparisonOperator::LessOrEqual: return paramValue.intValue <= condValue.intValue;
291 }
292 break;
293
296 return paramValue.stringValue == condValue.stringValue;
298 return paramValue.stringValue != condValue.stringValue;
299 break;
300 }
301
302 return false;
303 }
304
306 {
307 // All conditions must be true
308 for (const auto& condition : transition.conditions)
309 {
311 return false;
312 }
313 return true;
314 }
315
317 {
318 // Check transitions sorted by priority (higher priority first)
319 // First check "ANY" transitions, then specific transitions
320 const Transition* anyTransition = nullptr;
321
322 for (const auto& trans : m_transitions)
323 {
324 if (trans.fromState == "ANY")
325 {
327 {
328 if (!anyTransition)
330 }
331 }
332 else if (trans.fromState == m_currentState)
333 {
335 return &trans; // Specific transitions take priority
336 }
337 }
338
339 return anyTransition; // Return ANY transition if no specific transition found
340 }
341
342} // namespace OlympeAnimation
nlohmann::json json
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
std::unordered_map< std::string, ParameterValue > m_parameters
float GetParameterFloat(const std::string &name, float defaultValue=0.0f) const
bool ParseJSON(const std::string &jsonContent)
bool LoadFromFile(const std::string &filePath)
std::string GetParameterString(const std::string &name, const std::string &defaultValue="") const
bool EvaluateCondition(const Condition &condition) const
int GetParameterInt(const std::string &name, int defaultValue=0) const
bool GetParameterBool(const std::string &name, bool defaultValue=false) const
std::vector< Transition > m_transitions
void SetParameter(const std::string &name, bool value)
void SetCurrentState(const std::string &stateName)
std::string GetCurrentAnimationName() const
bool EvaluateTransition(const Transition &transition) const
const Transition * FindValidTransition() const
std::unordered_map< std::string, AnimationState > m_states
std::string GetString(const json &j, const std::string &key, const std::string &defaultValue="")
Safely get a string value from JSON.
bool LoadJsonFromFile(const std::string &filepath, json &j)
Load and parse a JSON file.
Definition json_helper.h:42
int GetInt(const json &j, const std::string &key, int defaultValue=0)
Safely get an integer value from JSON.
float GetFloat(const json &j, const std::string &key, float defaultValue=0.0f)
Safely get a float value from JSON.
bool GetBool(const json &j, const std::string &key, bool defaultValue=false)
Safely get a boolean value from JSON.
nlohmann::json json
#define SYSTEM_LOG