1 | /**************************************************************************/ |
2 | /* animation_node_state_machine.h */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #ifndef ANIMATION_NODE_STATE_MACHINE_H |
32 | #define ANIMATION_NODE_STATE_MACHINE_H |
33 | |
34 | #include "core/math/expression.h" |
35 | #include "scene/animation/animation_tree.h" |
36 | |
37 | class AnimationNodeStateMachineTransition : public Resource { |
38 | GDCLASS(AnimationNodeStateMachineTransition, Resource); |
39 | |
40 | public: |
41 | enum SwitchMode { |
42 | SWITCH_MODE_IMMEDIATE, |
43 | SWITCH_MODE_SYNC, |
44 | SWITCH_MODE_AT_END, |
45 | }; |
46 | |
47 | enum AdvanceMode { |
48 | ADVANCE_MODE_DISABLED, |
49 | ADVANCE_MODE_ENABLED, |
50 | ADVANCE_MODE_AUTO, |
51 | }; |
52 | |
53 | private: |
54 | SwitchMode switch_mode = SWITCH_MODE_IMMEDIATE; |
55 | AdvanceMode advance_mode = ADVANCE_MODE_ENABLED; |
56 | StringName advance_condition; |
57 | StringName advance_condition_name; |
58 | float xfade_time = 0.0; |
59 | Ref<Curve> xfade_curve; |
60 | bool reset = true; |
61 | int priority = 1; |
62 | String advance_expression; |
63 | |
64 | friend class AnimationNodeStateMachinePlayback; |
65 | Ref<Expression> expression; |
66 | |
67 | protected: |
68 | static void _bind_methods(); |
69 | |
70 | public: |
71 | void set_switch_mode(SwitchMode p_mode); |
72 | SwitchMode get_switch_mode() const; |
73 | |
74 | void set_advance_mode(AdvanceMode p_mode); |
75 | AdvanceMode get_advance_mode() const; |
76 | |
77 | void set_advance_condition(const StringName &p_condition); |
78 | StringName get_advance_condition() const; |
79 | |
80 | StringName get_advance_condition_name() const; |
81 | |
82 | void set_advance_expression(const String &p_expression); |
83 | String get_advance_expression() const; |
84 | |
85 | void set_xfade_time(float p_xfade); |
86 | float get_xfade_time() const; |
87 | |
88 | void set_reset(bool p_reset); |
89 | bool is_reset() const; |
90 | |
91 | void set_xfade_curve(const Ref<Curve> &p_curve); |
92 | Ref<Curve> get_xfade_curve() const; |
93 | |
94 | void set_priority(int p_priority); |
95 | int get_priority() const; |
96 | |
97 | AnimationNodeStateMachineTransition(); |
98 | }; |
99 | |
100 | VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode) |
101 | VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::AdvanceMode) |
102 | |
103 | class AnimationNodeStateMachinePlayback; |
104 | |
105 | class AnimationNodeStateMachine : public AnimationRootNode { |
106 | GDCLASS(AnimationNodeStateMachine, AnimationRootNode); |
107 | |
108 | public: |
109 | enum StateMachineType { |
110 | STATE_MACHINE_TYPE_ROOT, |
111 | STATE_MACHINE_TYPE_NESTED, |
112 | STATE_MACHINE_TYPE_GROUPED, |
113 | }; |
114 | |
115 | private: |
116 | friend class AnimationNodeStateMachinePlayback; |
117 | |
118 | StateMachineType state_machine_type = STATE_MACHINE_TYPE_ROOT; |
119 | |
120 | struct State { |
121 | Ref<AnimationRootNode> node; |
122 | Vector2 position; |
123 | }; |
124 | |
125 | HashMap<StringName, State> states; |
126 | bool allow_transition_to_self = false; |
127 | bool reset_ends = false; |
128 | |
129 | struct Transition { |
130 | StringName from; |
131 | StringName to; |
132 | Ref<AnimationNodeStateMachineTransition> transition; |
133 | }; |
134 | |
135 | Vector<Transition> transitions; |
136 | |
137 | StringName playback = "playback" ; |
138 | bool updating_transitions = false; |
139 | |
140 | Vector2 graph_offset; |
141 | |
142 | void _remove_transition(const Ref<AnimationNodeStateMachineTransition> p_transition); |
143 | void _rename_transitions(const StringName &p_name, const StringName &p_new_name); |
144 | bool _can_connect(const StringName &p_name); |
145 | |
146 | protected: |
147 | static void _bind_methods(); |
148 | |
149 | bool _set(const StringName &p_name, const Variant &p_value); |
150 | bool _get(const StringName &p_name, Variant &r_ret) const; |
151 | void _get_property_list(List<PropertyInfo> *p_list) const; |
152 | void _validate_property(PropertyInfo &p_property) const; |
153 | |
154 | bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const; |
155 | |
156 | virtual void _tree_changed() override; |
157 | virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) override; |
158 | virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node) override; |
159 | |
160 | virtual void reset_state() override; |
161 | |
162 | public: |
163 | StringName start_node = "Start" ; |
164 | StringName end_node = "End" ; |
165 | |
166 | virtual void get_parameter_list(List<PropertyInfo> *r_list) const override; |
167 | virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; |
168 | virtual bool is_parameter_read_only(const StringName &p_parameter) const override; |
169 | |
170 | void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2()); |
171 | void replace_node(const StringName &p_name, Ref<AnimationNode> p_node); |
172 | Ref<AnimationNode> get_node(const StringName &p_name) const; |
173 | void remove_node(const StringName &p_name); |
174 | void rename_node(const StringName &p_name, const StringName &p_new_name); |
175 | bool has_node(const StringName &p_name) const; |
176 | StringName get_node_name(const Ref<AnimationNode> &p_node) const; |
177 | void get_node_list(List<StringName> *r_nodes) const; |
178 | |
179 | void set_node_position(const StringName &p_name, const Vector2 &p_position); |
180 | Vector2 get_node_position(const StringName &p_name) const; |
181 | |
182 | virtual void get_child_nodes(List<ChildNode> *r_child_nodes) override; |
183 | |
184 | bool has_transition(const StringName &p_from, const StringName &p_to) const; |
185 | bool has_transition_from(const StringName &p_from) const; |
186 | bool has_transition_to(const StringName &p_to) const; |
187 | int find_transition(const StringName &p_from, const StringName &p_to) const; |
188 | Vector<int> find_transition_from(const StringName &p_from) const; |
189 | Vector<int> find_transition_to(const StringName &p_to) const; |
190 | void add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition); |
191 | Ref<AnimationNodeStateMachineTransition> get_transition(int p_transition) const; |
192 | StringName get_transition_from(int p_transition) const; |
193 | StringName get_transition_to(int p_transition) const; |
194 | int get_transition_count() const; |
195 | bool is_transition_across_group(int p_transition) const; |
196 | void remove_transition_by_index(const int p_transition); |
197 | void remove_transition(const StringName &p_from, const StringName &p_to); |
198 | |
199 | void set_state_machine_type(StateMachineType p_state_machine_type); |
200 | StateMachineType get_state_machine_type() const; |
201 | |
202 | void set_allow_transition_to_self(bool p_enable); |
203 | bool is_allow_transition_to_self() const; |
204 | |
205 | void set_reset_ends(bool p_enable); |
206 | bool are_ends_reset() const; |
207 | |
208 | bool can_edit_node(const StringName &p_name) const; |
209 | |
210 | void set_graph_offset(const Vector2 &p_offset); |
211 | Vector2 get_graph_offset() const; |
212 | |
213 | virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override; |
214 | virtual String get_caption() const override; |
215 | |
216 | virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) const override; |
217 | |
218 | AnimationNodeStateMachine(); |
219 | }; |
220 | |
221 | VARIANT_ENUM_CAST(AnimationNodeStateMachine::StateMachineType); |
222 | |
223 | class AnimationNodeStateMachinePlayback : public Resource { |
224 | GDCLASS(AnimationNodeStateMachinePlayback, Resource); |
225 | |
226 | friend class AnimationNodeStateMachine; |
227 | |
228 | struct AStarCost { |
229 | float distance = 0.0; |
230 | StringName prev; |
231 | }; |
232 | |
233 | struct TransitionInfo { |
234 | StringName from; |
235 | StringName to; |
236 | StringName next; |
237 | }; |
238 | |
239 | struct NextInfo { |
240 | StringName node; |
241 | double xfade; |
242 | Ref<Curve> curve; |
243 | AnimationNodeStateMachineTransition::SwitchMode switch_mode; |
244 | bool is_reset; |
245 | }; |
246 | |
247 | struct ChildStateMachineInfo { |
248 | Ref<AnimationNodeStateMachinePlayback> playback; |
249 | Vector<StringName> path; |
250 | bool is_reset = false; |
251 | }; |
252 | |
253 | Ref<AnimationNodeStateMachineTransition> default_transition; |
254 | String base_path; |
255 | |
256 | double len_fade_from = 0.0; |
257 | double pos_fade_from = 0.0; |
258 | |
259 | double len_current = 0.0; |
260 | double pos_current = 0.0; |
261 | |
262 | StringName current; |
263 | Ref<Curve> current_curve; |
264 | |
265 | Ref<AnimationNodeStateMachineTransition> group_start_transition; |
266 | Ref<AnimationNodeStateMachineTransition> group_end_transition; |
267 | |
268 | StringName fading_from; |
269 | float fading_time = 0.0; |
270 | float fading_pos = 0.0; |
271 | |
272 | Vector<StringName> path; |
273 | bool playing = false; |
274 | |
275 | StringName start_request; |
276 | StringName travel_request; |
277 | bool reset_request = false; |
278 | bool reset_request_on_teleport = false; |
279 | bool _reset_request_for_fading_from = false; |
280 | bool next_request = false; |
281 | bool stop_request = false; |
282 | bool teleport_request = false; |
283 | |
284 | bool is_grouped = false; |
285 | |
286 | void _travel_main(const StringName &p_state, bool p_reset_on_teleport = true); |
287 | void _start_main(const StringName &p_state, bool p_reset = true); |
288 | void _next_main(); |
289 | void _stop_main(); |
290 | |
291 | bool _make_travel_path(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, Vector<StringName> &r_path, bool p_test_only); |
292 | String _validate_path(AnimationNodeStateMachine *p_state_machine, const String &p_path); |
293 | bool _travel(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, bool p_test_only); |
294 | void _start(AnimationNodeStateMachine *p_state_machine); |
295 | |
296 | void _clear_path_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only); |
297 | bool _travel_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_is_allow_transition_to_self, bool p_is_parent_same_state, bool p_test_only); |
298 | void _start_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_test_only); |
299 | |
300 | double process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only); |
301 | double _process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only); |
302 | |
303 | bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const; |
304 | bool _transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only); |
305 | NextInfo _find_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine) const; |
306 | Ref<AnimationNodeStateMachineTransition> _check_group_transition(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const AnimationNodeStateMachine::Transition &p_transition, Ref<AnimationNodeStateMachine> &r_state_machine, bool &r_bypass) const; |
307 | bool _can_transition_to_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, NextInfo p_next, bool p_test_only); |
308 | |
309 | void _set_current(AnimationNodeStateMachine *p_state_machine, const StringName &p_state); |
310 | void _set_grouped(bool p_is_grouped); |
311 | void _set_base_path(const String &p_base_path); |
312 | Ref<AnimationNodeStateMachinePlayback> _get_parent_playback(AnimationTree *p_tree) const; |
313 | Ref<AnimationNodeStateMachine> _get_parent_state_machine(AnimationTree *p_tree) const; |
314 | Ref<AnimationNodeStateMachineTransition> _get_group_start_transition() const; |
315 | Ref<AnimationNodeStateMachineTransition> _get_group_end_transition() const; |
316 | |
317 | TypedArray<StringName> _get_travel_path() const; |
318 | |
319 | protected: |
320 | static void _bind_methods(); |
321 | |
322 | public: |
323 | void travel(const StringName &p_state, bool p_reset_on_teleport = true); |
324 | void start(const StringName &p_state, bool p_reset = true); |
325 | void next(); |
326 | void stop(); |
327 | bool is_playing() const; |
328 | bool is_end() const; |
329 | StringName get_current_node() const; |
330 | StringName get_fading_from_node() const; |
331 | Vector<StringName> get_travel_path() const; |
332 | float get_current_play_pos() const; |
333 | float get_current_length() const; |
334 | |
335 | float get_fade_from_play_pos() const; |
336 | float get_fade_from_length() const; |
337 | |
338 | float get_fading_time() const; |
339 | float get_fading_pos() const; |
340 | |
341 | void clear_path(); |
342 | void push_path(const StringName &p_state); |
343 | |
344 | AnimationNodeStateMachinePlayback(); |
345 | }; |
346 | |
347 | #endif // ANIMATION_NODE_STATE_MACHINE_H |
348 | |