1/**************************************************************************/
2/* skeleton_modification_2d_jiggle.cpp */
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#include "skeleton_modification_2d_jiggle.h"
32
33#include "scene/2d/skeleton_2d.h"
34#include "scene/resources/world_2d.h"
35
36bool SkeletonModification2DJiggle::_set(const StringName &p_path, const Variant &p_value) {
37 String path = p_path;
38
39 if (path.begins_with("joint_data/")) {
40 int which = path.get_slicec('/', 1).to_int();
41 String what = path.get_slicec('/', 2);
42 ERR_FAIL_INDEX_V(which, jiggle_data_chain.size(), false);
43
44 if (what == "bone2d_node") {
45 set_jiggle_joint_bone2d_node(which, p_value);
46 } else if (what == "bone_index") {
47 set_jiggle_joint_bone_index(which, p_value);
48 } else if (what == "override_defaults") {
49 set_jiggle_joint_override(which, p_value);
50 } else if (what == "stiffness") {
51 set_jiggle_joint_stiffness(which, p_value);
52 } else if (what == "mass") {
53 set_jiggle_joint_mass(which, p_value);
54 } else if (what == "damping") {
55 set_jiggle_joint_damping(which, p_value);
56 } else if (what == "use_gravity") {
57 set_jiggle_joint_use_gravity(which, p_value);
58 } else if (what == "gravity") {
59 set_jiggle_joint_gravity(which, p_value);
60 }
61 return true;
62 } else {
63 if (path == "use_colliders") {
64 set_use_colliders(p_value);
65 } else if (path == "collision_mask") {
66 set_collision_mask(p_value);
67 }
68 }
69 return true;
70}
71
72bool SkeletonModification2DJiggle::_get(const StringName &p_path, Variant &r_ret) const {
73 String path = p_path;
74
75 if (path.begins_with("joint_data/")) {
76 int which = path.get_slicec('/', 1).to_int();
77 String what = path.get_slicec('/', 2);
78 ERR_FAIL_INDEX_V(which, jiggle_data_chain.size(), false);
79
80 if (what == "bone2d_node") {
81 r_ret = get_jiggle_joint_bone2d_node(which);
82 } else if (what == "bone_index") {
83 r_ret = get_jiggle_joint_bone_index(which);
84 } else if (what == "override_defaults") {
85 r_ret = get_jiggle_joint_override(which);
86 } else if (what == "stiffness") {
87 r_ret = get_jiggle_joint_stiffness(which);
88 } else if (what == "mass") {
89 r_ret = get_jiggle_joint_mass(which);
90 } else if (what == "damping") {
91 r_ret = get_jiggle_joint_damping(which);
92 } else if (what == "use_gravity") {
93 r_ret = get_jiggle_joint_use_gravity(which);
94 } else if (what == "gravity") {
95 r_ret = get_jiggle_joint_gravity(which);
96 }
97 return true;
98 } else {
99 if (path == "use_colliders") {
100 r_ret = get_use_colliders();
101 } else if (path == "collision_mask") {
102 r_ret = get_collision_mask();
103 }
104 }
105 return true;
106}
107
108void SkeletonModification2DJiggle::_get_property_list(List<PropertyInfo> *p_list) const {
109 p_list->push_back(PropertyInfo(Variant::BOOL, "use_colliders", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
110 if (use_colliders) {
111 p_list->push_back(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS, "", PROPERTY_USAGE_DEFAULT));
112 }
113
114 for (int i = 0; i < jiggle_data_chain.size(); i++) {
115 String base_string = "joint_data/" + itos(i) + "/";
116
117 p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
118 p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT));
119 p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "override_defaults", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
120
121 if (jiggle_data_chain[i].override_defaults) {
122 p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "stiffness", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT));
123 p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "mass", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT));
124 p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01", PROPERTY_USAGE_DEFAULT));
125 p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
126 if (jiggle_data_chain[i].use_gravity) {
127 p_list->push_back(PropertyInfo(Variant::VECTOR2, base_string + "gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
128 }
129 }
130 }
131}
132
133void SkeletonModification2DJiggle::_execute(float p_delta) {
134 ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
135 "Modification is not setup and therefore cannot execute!");
136 if (!enabled) {
137 return;
138 }
139 if (target_node_cache.is_null()) {
140 WARN_PRINT_ONCE("Target cache is out of date. Attempting to update...");
141 update_target_cache();
142 return;
143 }
144 Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache));
145 if (!target || !target->is_inside_tree()) {
146 ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!");
147 return;
148 }
149
150 for (int i = 0; i < jiggle_data_chain.size(); i++) {
151 _execute_jiggle_joint(i, target, p_delta);
152 }
153}
154
155void SkeletonModification2DJiggle::_execute_jiggle_joint(int p_joint_idx, Node2D *p_target, float p_delta) {
156 // Adopted from: https://wiki.unity3d.com/index.php/JiggleBone
157 // With modifications by TwistedTwigleg.
158
159 if (jiggle_data_chain[p_joint_idx].bone_idx <= -1 || jiggle_data_chain[p_joint_idx].bone_idx > stack->skeleton->get_bone_count()) {
160 ERR_PRINT_ONCE("Jiggle joint " + itos(p_joint_idx) + " bone index is invalid. Cannot execute modification on joint...");
161 return;
162 }
163
164 if (jiggle_data_chain[p_joint_idx].bone2d_node_cache.is_null() && !jiggle_data_chain[p_joint_idx].bone2d_node.is_empty()) {
165 WARN_PRINT_ONCE("Bone2D cache for joint " + itos(p_joint_idx) + " is out of date. Updating...");
166 jiggle_joint_update_bone2d_cache(p_joint_idx);
167 }
168
169 Bone2D *operation_bone = stack->skeleton->get_bone(jiggle_data_chain[p_joint_idx].bone_idx);
170 if (!operation_bone) {
171 ERR_PRINT_ONCE("Jiggle joint " + itos(p_joint_idx) + " does not have a Bone2D node or it cannot be found!");
172 return;
173 }
174
175 Transform2D operation_bone_trans = operation_bone->get_global_transform();
176 Vector2 target_position = p_target->get_global_position();
177
178 jiggle_data_chain.write[p_joint_idx].force = (target_position - jiggle_data_chain[p_joint_idx].dynamic_position) * jiggle_data_chain[p_joint_idx].stiffness * p_delta;
179
180 if (jiggle_data_chain[p_joint_idx].use_gravity) {
181 jiggle_data_chain.write[p_joint_idx].force += jiggle_data_chain[p_joint_idx].gravity * p_delta;
182 }
183
184 jiggle_data_chain.write[p_joint_idx].acceleration = jiggle_data_chain[p_joint_idx].force / jiggle_data_chain[p_joint_idx].mass;
185 jiggle_data_chain.write[p_joint_idx].velocity += jiggle_data_chain[p_joint_idx].acceleration * (1 - jiggle_data_chain[p_joint_idx].damping);
186
187 jiggle_data_chain.write[p_joint_idx].dynamic_position += jiggle_data_chain[p_joint_idx].velocity + jiggle_data_chain[p_joint_idx].force;
188 jiggle_data_chain.write[p_joint_idx].dynamic_position += operation_bone_trans.get_origin() - jiggle_data_chain[p_joint_idx].last_position;
189 jiggle_data_chain.write[p_joint_idx].last_position = operation_bone_trans.get_origin();
190
191 // Collision detection/response
192 if (use_colliders) {
193 if (execution_mode == SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_physics_process) {
194 Ref<World2D> world_2d = stack->skeleton->get_world_2d();
195 ERR_FAIL_COND(world_2d.is_null());
196 PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
197 PhysicsDirectSpaceState2D::RayResult ray_result;
198
199 PhysicsDirectSpaceState2D::RayParameters ray_params;
200 ray_params.from = operation_bone_trans.get_origin();
201 ray_params.to = jiggle_data_chain[p_joint_idx].dynamic_position;
202 ray_params.collision_mask = collision_mask;
203
204 // Add exception support?
205 bool ray_hit = space_state->intersect_ray(ray_params, ray_result);
206
207 if (ray_hit) {
208 jiggle_data_chain.write[p_joint_idx].dynamic_position = jiggle_data_chain[p_joint_idx].last_noncollision_position;
209 jiggle_data_chain.write[p_joint_idx].acceleration = Vector2(0, 0);
210 jiggle_data_chain.write[p_joint_idx].velocity = Vector2(0, 0);
211 } else {
212 jiggle_data_chain.write[p_joint_idx].last_noncollision_position = jiggle_data_chain[p_joint_idx].dynamic_position;
213 }
214 } else {
215 WARN_PRINT_ONCE("Jiggle 2D modifier: You cannot detect colliders without the stack mode being set to _physics_process!");
216 }
217 }
218
219 // Rotate the bone using the dynamic position!
220 operation_bone_trans = operation_bone_trans.looking_at(jiggle_data_chain[p_joint_idx].dynamic_position);
221 operation_bone_trans.set_rotation(operation_bone_trans.get_rotation() - operation_bone->get_bone_angle());
222
223 // Reset scale
224 operation_bone_trans.set_scale(operation_bone->get_global_scale());
225
226 operation_bone->set_global_transform(operation_bone_trans);
227 stack->skeleton->set_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx, operation_bone->get_transform(), stack->strength, true);
228}
229
230void SkeletonModification2DJiggle::_update_jiggle_joint_data() {
231 for (int i = 0; i < jiggle_data_chain.size(); i++) {
232 if (!jiggle_data_chain[i].override_defaults) {
233 set_jiggle_joint_stiffness(i, stiffness);
234 set_jiggle_joint_mass(i, mass);
235 set_jiggle_joint_damping(i, damping);
236 set_jiggle_joint_use_gravity(i, use_gravity);
237 set_jiggle_joint_gravity(i, gravity);
238 }
239 }
240}
241
242void SkeletonModification2DJiggle::_setup_modification(SkeletonModificationStack2D *p_stack) {
243 stack = p_stack;
244
245 if (stack) {
246 is_setup = true;
247
248 if (stack->skeleton) {
249 for (int i = 0; i < jiggle_data_chain.size(); i++) {
250 int bone_idx = jiggle_data_chain[i].bone_idx;
251 if (bone_idx > 0 && bone_idx < stack->skeleton->get_bone_count()) {
252 Bone2D *bone2d_node = stack->skeleton->get_bone(bone_idx);
253 jiggle_data_chain.write[i].dynamic_position = bone2d_node->get_global_position();
254 }
255 }
256 }
257
258 update_target_cache();
259 }
260}
261
262void SkeletonModification2DJiggle::update_target_cache() {
263 if (!is_setup || !stack) {
264 ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!");
265 return;
266 }
267
268 target_node_cache = ObjectID();
269 if (stack->skeleton) {
270 if (stack->skeleton->is_inside_tree()) {
271 if (stack->skeleton->has_node(target_node)) {
272 Node *node = stack->skeleton->get_node(target_node);
273 ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
274 "Cannot update target cache: node is this modification's skeleton or cannot be found!");
275 ERR_FAIL_COND_MSG(!node->is_inside_tree(),
276 "Cannot update target cache: node is not in scene tree!");
277 target_node_cache = node->get_instance_id();
278 }
279 }
280 }
281}
282
283void SkeletonModification2DJiggle::jiggle_joint_update_bone2d_cache(int p_joint_idx) {
284 ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Cannot update bone2d cache: joint index out of range!");
285 if (!is_setup || !stack) {
286 ERR_PRINT_ONCE("Cannot update Jiggle " + itos(p_joint_idx) + " Bone2D cache: modification is not properly setup!");
287 return;
288 }
289
290 jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = ObjectID();
291 if (stack->skeleton) {
292 if (stack->skeleton->is_inside_tree()) {
293 if (stack->skeleton->has_node(jiggle_data_chain[p_joint_idx].bone2d_node)) {
294 Node *node = stack->skeleton->get_node(jiggle_data_chain[p_joint_idx].bone2d_node);
295 ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
296 "Cannot update Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: node is this modification's skeleton or cannot be found!");
297 ERR_FAIL_COND_MSG(!node->is_inside_tree(),
298 "Cannot update Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: node is not in scene tree!");
299 jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = node->get_instance_id();
300
301 Bone2D *bone = Object::cast_to<Bone2D>(node);
302 if (bone) {
303 jiggle_data_chain.write[p_joint_idx].bone_idx = bone->get_index_in_skeleton();
304 } else {
305 ERR_FAIL_MSG("Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: Nodepath to Bone2D is not a Bone2D node!");
306 }
307 }
308 }
309 }
310}
311
312void SkeletonModification2DJiggle::set_target_node(const NodePath &p_target_node) {
313 target_node = p_target_node;
314 update_target_cache();
315}
316
317NodePath SkeletonModification2DJiggle::get_target_node() const {
318 return target_node;
319}
320
321void SkeletonModification2DJiggle::set_stiffness(float p_stiffness) {
322 ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!");
323 stiffness = p_stiffness;
324 _update_jiggle_joint_data();
325}
326
327float SkeletonModification2DJiggle::get_stiffness() const {
328 return stiffness;
329}
330
331void SkeletonModification2DJiggle::set_mass(float p_mass) {
332 ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!");
333 mass = p_mass;
334 _update_jiggle_joint_data();
335}
336
337float SkeletonModification2DJiggle::get_mass() const {
338 return mass;
339}
340
341void SkeletonModification2DJiggle::set_damping(float p_damping) {
342 ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!");
343 ERR_FAIL_COND_MSG(p_damping > 1, "Damping cannot be more than one!");
344 damping = p_damping;
345 _update_jiggle_joint_data();
346}
347
348float SkeletonModification2DJiggle::get_damping() const {
349 return damping;
350}
351
352void SkeletonModification2DJiggle::set_use_gravity(bool p_use_gravity) {
353 use_gravity = p_use_gravity;
354 _update_jiggle_joint_data();
355}
356
357bool SkeletonModification2DJiggle::get_use_gravity() const {
358 return use_gravity;
359}
360
361void SkeletonModification2DJiggle::set_gravity(Vector2 p_gravity) {
362 gravity = p_gravity;
363 _update_jiggle_joint_data();
364}
365
366Vector2 SkeletonModification2DJiggle::get_gravity() const {
367 return gravity;
368}
369
370void SkeletonModification2DJiggle::set_use_colliders(bool p_use_colliders) {
371 use_colliders = p_use_colliders;
372 notify_property_list_changed();
373}
374
375bool SkeletonModification2DJiggle::get_use_colliders() const {
376 return use_colliders;
377}
378
379void SkeletonModification2DJiggle::set_collision_mask(int p_mask) {
380 collision_mask = p_mask;
381}
382
383int SkeletonModification2DJiggle::get_collision_mask() const {
384 return collision_mask;
385}
386
387// Jiggle joint data functions
388int SkeletonModification2DJiggle::get_jiggle_data_chain_length() {
389 return jiggle_data_chain.size();
390}
391
392void SkeletonModification2DJiggle::set_jiggle_data_chain_length(int p_length) {
393 ERR_FAIL_COND(p_length < 0);
394 jiggle_data_chain.resize(p_length);
395 notify_property_list_changed();
396}
397
398void SkeletonModification2DJiggle::set_jiggle_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node) {
399 ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Jiggle joint out of range!");
400 jiggle_data_chain.write[p_joint_idx].bone2d_node = p_target_node;
401 jiggle_joint_update_bone2d_cache(p_joint_idx);
402
403 notify_property_list_changed();
404}
405
406NodePath SkeletonModification2DJiggle::get_jiggle_joint_bone2d_node(int p_joint_idx) const {
407 ERR_FAIL_INDEX_V_MSG(p_joint_idx, jiggle_data_chain.size(), NodePath(), "Jiggle joint out of range!");
408 return jiggle_data_chain[p_joint_idx].bone2d_node;
409}
410
411void SkeletonModification2DJiggle::set_jiggle_joint_bone_index(int p_joint_idx, int p_bone_idx) {
412 ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Jiggle joint out of range!");
413 ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
414
415 if (is_setup) {
416 if (stack->skeleton) {
417 ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
418 jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
419 jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id();
420 jiggle_data_chain.write[p_joint_idx].bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx));
421 } else {
422 WARN_PRINT("Cannot verify the Jiggle joint " + itos(p_joint_idx) + " bone index for this modification...");
423 jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
424 }
425 } else {
426 WARN_PRINT("Cannot verify the Jiggle joint " + itos(p_joint_idx) + " bone index for this modification...");
427 jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx;
428 }
429
430 notify_property_list_changed();
431}
432
433int SkeletonModification2DJiggle::get_jiggle_joint_bone_index(int p_joint_idx) const {
434 ERR_FAIL_INDEX_V_MSG(p_joint_idx, jiggle_data_chain.size(), -1, "Jiggle joint out of range!");
435 return jiggle_data_chain[p_joint_idx].bone_idx;
436}
437
438void SkeletonModification2DJiggle::set_jiggle_joint_override(int p_joint_idx, bool p_override) {
439 ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
440 jiggle_data_chain.write[p_joint_idx].override_defaults = p_override;
441 _update_jiggle_joint_data();
442 notify_property_list_changed();
443}
444
445bool SkeletonModification2DJiggle::get_jiggle_joint_override(int p_joint_idx) const {
446 ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), false);
447 return jiggle_data_chain[p_joint_idx].override_defaults;
448}
449
450void SkeletonModification2DJiggle::set_jiggle_joint_stiffness(int p_joint_idx, float p_stiffness) {
451 ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!");
452 ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
453 jiggle_data_chain.write[p_joint_idx].stiffness = p_stiffness;
454}
455
456float SkeletonModification2DJiggle::get_jiggle_joint_stiffness(int p_joint_idx) const {
457 ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1);
458 return jiggle_data_chain[p_joint_idx].stiffness;
459}
460
461void SkeletonModification2DJiggle::set_jiggle_joint_mass(int p_joint_idx, float p_mass) {
462 ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!");
463 ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
464 jiggle_data_chain.write[p_joint_idx].mass = p_mass;
465}
466
467float SkeletonModification2DJiggle::get_jiggle_joint_mass(int p_joint_idx) const {
468 ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1);
469 return jiggle_data_chain[p_joint_idx].mass;
470}
471
472void SkeletonModification2DJiggle::set_jiggle_joint_damping(int p_joint_idx, float p_damping) {
473 ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!");
474 ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
475 jiggle_data_chain.write[p_joint_idx].damping = p_damping;
476}
477
478float SkeletonModification2DJiggle::get_jiggle_joint_damping(int p_joint_idx) const {
479 ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1);
480 return jiggle_data_chain[p_joint_idx].damping;
481}
482
483void SkeletonModification2DJiggle::set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity) {
484 ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
485 jiggle_data_chain.write[p_joint_idx].use_gravity = p_use_gravity;
486 notify_property_list_changed();
487}
488
489bool SkeletonModification2DJiggle::get_jiggle_joint_use_gravity(int p_joint_idx) const {
490 ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), false);
491 return jiggle_data_chain[p_joint_idx].use_gravity;
492}
493
494void SkeletonModification2DJiggle::set_jiggle_joint_gravity(int p_joint_idx, Vector2 p_gravity) {
495 ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size());
496 jiggle_data_chain.write[p_joint_idx].gravity = p_gravity;
497}
498
499Vector2 SkeletonModification2DJiggle::get_jiggle_joint_gravity(int p_joint_idx) const {
500 ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), Vector2(0, 0));
501 return jiggle_data_chain[p_joint_idx].gravity;
502}
503
504void SkeletonModification2DJiggle::_bind_methods() {
505 ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DJiggle::set_target_node);
506 ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DJiggle::get_target_node);
507
508 ClassDB::bind_method(D_METHOD("set_jiggle_data_chain_length", "length"), &SkeletonModification2DJiggle::set_jiggle_data_chain_length);
509 ClassDB::bind_method(D_METHOD("get_jiggle_data_chain_length"), &SkeletonModification2DJiggle::get_jiggle_data_chain_length);
510
511 ClassDB::bind_method(D_METHOD("set_stiffness", "stiffness"), &SkeletonModification2DJiggle::set_stiffness);
512 ClassDB::bind_method(D_METHOD("get_stiffness"), &SkeletonModification2DJiggle::get_stiffness);
513 ClassDB::bind_method(D_METHOD("set_mass", "mass"), &SkeletonModification2DJiggle::set_mass);
514 ClassDB::bind_method(D_METHOD("get_mass"), &SkeletonModification2DJiggle::get_mass);
515 ClassDB::bind_method(D_METHOD("set_damping", "damping"), &SkeletonModification2DJiggle::set_damping);
516 ClassDB::bind_method(D_METHOD("get_damping"), &SkeletonModification2DJiggle::get_damping);
517 ClassDB::bind_method(D_METHOD("set_use_gravity", "use_gravity"), &SkeletonModification2DJiggle::set_use_gravity);
518 ClassDB::bind_method(D_METHOD("get_use_gravity"), &SkeletonModification2DJiggle::get_use_gravity);
519 ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &SkeletonModification2DJiggle::set_gravity);
520 ClassDB::bind_method(D_METHOD("get_gravity"), &SkeletonModification2DJiggle::get_gravity);
521
522 ClassDB::bind_method(D_METHOD("set_use_colliders", "use_colliders"), &SkeletonModification2DJiggle::set_use_colliders);
523 ClassDB::bind_method(D_METHOD("get_use_colliders"), &SkeletonModification2DJiggle::get_use_colliders);
524 ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SkeletonModification2DJiggle::set_collision_mask);
525 ClassDB::bind_method(D_METHOD("get_collision_mask"), &SkeletonModification2DJiggle::get_collision_mask);
526
527 // Jiggle joint data functions
528 ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone2d_node", "joint_idx", "bone2d_node"), &SkeletonModification2DJiggle::set_jiggle_joint_bone2d_node);
529 ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone2d_node", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_bone2d_node);
530 ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification2DJiggle::set_jiggle_joint_bone_index);
531 ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_index", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_bone_index);
532 ClassDB::bind_method(D_METHOD("set_jiggle_joint_override", "joint_idx", "override"), &SkeletonModification2DJiggle::set_jiggle_joint_override);
533 ClassDB::bind_method(D_METHOD("get_jiggle_joint_override", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_override);
534 ClassDB::bind_method(D_METHOD("set_jiggle_joint_stiffness", "joint_idx", "stiffness"), &SkeletonModification2DJiggle::set_jiggle_joint_stiffness);
535 ClassDB::bind_method(D_METHOD("get_jiggle_joint_stiffness", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_stiffness);
536 ClassDB::bind_method(D_METHOD("set_jiggle_joint_mass", "joint_idx", "mass"), &SkeletonModification2DJiggle::set_jiggle_joint_mass);
537 ClassDB::bind_method(D_METHOD("get_jiggle_joint_mass", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_mass);
538 ClassDB::bind_method(D_METHOD("set_jiggle_joint_damping", "joint_idx", "damping"), &SkeletonModification2DJiggle::set_jiggle_joint_damping);
539 ClassDB::bind_method(D_METHOD("get_jiggle_joint_damping", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_damping);
540 ClassDB::bind_method(D_METHOD("set_jiggle_joint_use_gravity", "joint_idx", "use_gravity"), &SkeletonModification2DJiggle::set_jiggle_joint_use_gravity);
541 ClassDB::bind_method(D_METHOD("get_jiggle_joint_use_gravity", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_use_gravity);
542 ClassDB::bind_method(D_METHOD("set_jiggle_joint_gravity", "joint_idx", "gravity"), &SkeletonModification2DJiggle::set_jiggle_joint_gravity);
543 ClassDB::bind_method(D_METHOD("get_jiggle_joint_gravity", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_gravity);
544
545 ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node");
546 ADD_PROPERTY(PropertyInfo(Variant::INT, "jiggle_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_jiggle_data_chain_length", "get_jiggle_data_chain_length");
547 ADD_GROUP("Default Joint Settings", "");
548 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness"), "set_stiffness", "get_stiffness");
549 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass"), "set_mass", "get_mass");
550 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01"), "set_damping", "get_damping");
551 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_gravity"), "set_use_gravity", "get_use_gravity");
552 ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity"), "set_gravity", "get_gravity");
553 ADD_GROUP("", "");
554}
555
556SkeletonModification2DJiggle::SkeletonModification2DJiggle() {
557 stack = nullptr;
558 is_setup = false;
559 jiggle_data_chain = Vector<Jiggle_Joint_Data2D>();
560 stiffness = 3;
561 mass = 0.75;
562 damping = 0.75;
563 use_gravity = false;
564 gravity = Vector2(0, 6.0);
565 enabled = true;
566 editor_draw_gizmo = false; // Nothing to really show in a gizmo right now.
567}
568
569SkeletonModification2DJiggle::~SkeletonModification2DJiggle() {
570}
571