Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/2d/physics/physical_bone_2d.cpp
9906 views
1
/**************************************************************************/
2
/* physical_bone_2d.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 "physical_bone_2d.h"
32
33
#include "scene/2d/physics/joints/joint_2d.h"
34
35
void PhysicalBone2D::_notification(int p_what) {
36
switch (p_what) {
37
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
38
// Position the RigidBody in the correct position.
39
if (follow_bone_when_simulating) {
40
_position_at_bone2d();
41
}
42
43
// Keep the child joint in the correct position.
44
if (child_joint && auto_configure_joint) {
45
child_joint->set_global_position(get_global_position());
46
}
47
} break;
48
49
case NOTIFICATION_READY: {
50
_find_skeleton_parent();
51
_find_joint_child();
52
53
// Configure joint.
54
if (child_joint && auto_configure_joint) {
55
_auto_configure_joint();
56
}
57
58
// Simulate physics if set.
59
if (simulate_physics) {
60
_start_physics_simulation();
61
} else {
62
_stop_physics_simulation();
63
}
64
65
set_physics_process_internal(true);
66
} break;
67
}
68
}
69
70
void PhysicalBone2D::_position_at_bone2d() {
71
// Reset to Bone2D position
72
if (parent_skeleton) {
73
Bone2D *bone_to_use = parent_skeleton->get_bone(bone2d_index);
74
ERR_FAIL_NULL_MSG(bone_to_use, "It's not possible to position the bone with ID: " + itos(bone2d_index) + ".");
75
set_global_transform(bone_to_use->get_global_transform());
76
}
77
}
78
79
void PhysicalBone2D::_find_skeleton_parent() {
80
Node *current_parent = get_parent();
81
82
while (current_parent != nullptr) {
83
Skeleton2D *potential_skeleton = Object::cast_to<Skeleton2D>(current_parent);
84
if (potential_skeleton) {
85
parent_skeleton = potential_skeleton;
86
break;
87
} else {
88
PhysicalBone2D *potential_parent_bone = Object::cast_to<PhysicalBone2D>(current_parent);
89
if (potential_parent_bone) {
90
current_parent = potential_parent_bone->get_parent();
91
} else {
92
current_parent = nullptr;
93
}
94
}
95
}
96
}
97
98
void PhysicalBone2D::_find_joint_child() {
99
for (int i = 0; i < get_child_count(); i++) {
100
Node *child_node = get_child(i);
101
Joint2D *potential_joint = Object::cast_to<Joint2D>(child_node);
102
if (potential_joint) {
103
child_joint = potential_joint;
104
break;
105
}
106
}
107
}
108
109
PackedStringArray PhysicalBone2D::get_configuration_warnings() const {
110
PackedStringArray warnings = RigidBody2D::get_configuration_warnings();
111
112
if (!parent_skeleton) {
113
warnings.push_back(RTR("A PhysicalBone2D only works with a Skeleton2D or another PhysicalBone2D as a parent node!"));
114
}
115
if (parent_skeleton && bone2d_index <= -1) {
116
warnings.push_back(RTR("A PhysicalBone2D needs to be assigned to a Bone2D node in order to function! Please set a Bone2D node in the inspector."));
117
}
118
if (!child_joint) {
119
PhysicalBone2D *parent_bone = Object::cast_to<PhysicalBone2D>(get_parent());
120
if (parent_bone) {
121
warnings.push_back(RTR("A PhysicalBone2D node should have a Joint2D-based child node to keep bones connected! Please add a Joint2D-based node as a child to this node!"));
122
}
123
}
124
125
return warnings;
126
}
127
128
void PhysicalBone2D::_auto_configure_joint() {
129
if (!auto_configure_joint) {
130
return;
131
}
132
133
if (child_joint) {
134
// Node A = parent | Node B = this node
135
Node *parent_node = get_parent();
136
PhysicalBone2D *potential_parent_bone = Object::cast_to<PhysicalBone2D>(parent_node);
137
138
if (potential_parent_bone) {
139
child_joint->set_node_a(child_joint->get_path_to(potential_parent_bone));
140
child_joint->set_node_b(child_joint->get_path_to(this));
141
} else {
142
WARN_PRINT("Cannot setup joint without a parent PhysicalBone2D node.");
143
}
144
145
// Place the child joint at this node's position.
146
child_joint->set_global_position(get_global_position());
147
}
148
}
149
150
void PhysicalBone2D::_start_physics_simulation() {
151
if (_internal_simulate_physics) {
152
return;
153
}
154
155
// Reset to Bone2D position.
156
_position_at_bone2d();
157
158
// Apply the layers and masks.
159
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
160
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
161
PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
162
163
// Apply the correct mode.
164
_apply_body_mode();
165
166
_internal_simulate_physics = true;
167
set_physics_process_internal(true);
168
}
169
170
void PhysicalBone2D::_stop_physics_simulation() {
171
if (_internal_simulate_physics) {
172
_internal_simulate_physics = false;
173
174
// Reset to Bone2D position
175
_position_at_bone2d();
176
177
set_physics_process_internal(false);
178
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0);
179
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0);
180
PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), 1.0);
181
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
182
}
183
}
184
185
Joint2D *PhysicalBone2D::get_joint() const {
186
return child_joint;
187
}
188
189
bool PhysicalBone2D::get_auto_configure_joint() const {
190
return auto_configure_joint;
191
}
192
193
void PhysicalBone2D::set_auto_configure_joint(bool p_auto_configure) {
194
auto_configure_joint = p_auto_configure;
195
_auto_configure_joint();
196
}
197
198
void PhysicalBone2D::set_simulate_physics(bool p_simulate) {
199
if (p_simulate == simulate_physics) {
200
return;
201
}
202
simulate_physics = p_simulate;
203
204
if (simulate_physics) {
205
_start_physics_simulation();
206
} else {
207
_stop_physics_simulation();
208
}
209
}
210
211
bool PhysicalBone2D::get_simulate_physics() const {
212
return simulate_physics;
213
}
214
215
bool PhysicalBone2D::is_simulating_physics() const {
216
return _internal_simulate_physics;
217
}
218
219
void PhysicalBone2D::set_bone2d_nodepath(const NodePath &p_nodepath) {
220
bone2d_nodepath = p_nodepath;
221
notify_property_list_changed();
222
}
223
224
NodePath PhysicalBone2D::get_bone2d_nodepath() const {
225
return bone2d_nodepath;
226
}
227
228
void PhysicalBone2D::set_bone2d_index(int p_bone_idx) {
229
ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
230
231
if (!is_inside_tree()) {
232
bone2d_index = p_bone_idx;
233
return;
234
}
235
236
if (parent_skeleton) {
237
ERR_FAIL_INDEX_MSG(p_bone_idx, parent_skeleton->get_bone_count(), "Passed-in Bone index is out of range!");
238
bone2d_index = p_bone_idx;
239
240
bone2d_nodepath = get_path_to(parent_skeleton->get_bone(bone2d_index));
241
} else {
242
WARN_PRINT("Cannot verify bone index...");
243
bone2d_index = p_bone_idx;
244
}
245
246
notify_property_list_changed();
247
}
248
249
int PhysicalBone2D::get_bone2d_index() const {
250
return bone2d_index;
251
}
252
253
void PhysicalBone2D::set_follow_bone_when_simulating(bool p_follow_bone) {
254
follow_bone_when_simulating = p_follow_bone;
255
256
if (_internal_simulate_physics) {
257
_stop_physics_simulation();
258
_start_physics_simulation();
259
}
260
}
261
262
bool PhysicalBone2D::get_follow_bone_when_simulating() const {
263
return follow_bone_when_simulating;
264
}
265
266
void PhysicalBone2D::_bind_methods() {
267
ClassDB::bind_method(D_METHOD("get_joint"), &PhysicalBone2D::get_joint);
268
ClassDB::bind_method(D_METHOD("get_auto_configure_joint"), &PhysicalBone2D::get_auto_configure_joint);
269
ClassDB::bind_method(D_METHOD("set_auto_configure_joint", "auto_configure_joint"), &PhysicalBone2D::set_auto_configure_joint);
270
271
ClassDB::bind_method(D_METHOD("set_simulate_physics", "simulate_physics"), &PhysicalBone2D::set_simulate_physics);
272
ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone2D::get_simulate_physics);
273
ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone2D::is_simulating_physics);
274
275
ClassDB::bind_method(D_METHOD("set_bone2d_nodepath", "nodepath"), &PhysicalBone2D::set_bone2d_nodepath);
276
ClassDB::bind_method(D_METHOD("get_bone2d_nodepath"), &PhysicalBone2D::get_bone2d_nodepath);
277
ClassDB::bind_method(D_METHOD("set_bone2d_index", "bone_index"), &PhysicalBone2D::set_bone2d_index);
278
ClassDB::bind_method(D_METHOD("get_bone2d_index"), &PhysicalBone2D::get_bone2d_index);
279
ClassDB::bind_method(D_METHOD("set_follow_bone_when_simulating", "follow_bone"), &PhysicalBone2D::set_follow_bone_when_simulating);
280
ClassDB::bind_method(D_METHOD("get_follow_bone_when_simulating"), &PhysicalBone2D::get_follow_bone_when_simulating);
281
282
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "bone2d_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D"), "set_bone2d_nodepath", "get_bone2d_nodepath");
283
ADD_PROPERTY(PropertyInfo(Variant::INT, "bone2d_index", PROPERTY_HINT_RANGE, "-1, 1000, 1"), "set_bone2d_index", "get_bone2d_index");
284
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_configure_joint"), "set_auto_configure_joint", "get_auto_configure_joint");
285
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simulate_physics"), "set_simulate_physics", "get_simulate_physics");
286
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_bone_when_simulating"), "set_follow_bone_when_simulating", "get_follow_bone_when_simulating");
287
}
288
289
PhysicalBone2D::PhysicalBone2D() {
290
// Stop the RigidBody from executing its force integration.
291
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0);
292
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0);
293
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
294
295
child_joint = nullptr;
296
}
297
298
PhysicalBone2D::~PhysicalBone2D() {
299
}
300
301