You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-06 12:20:30 +00:00
Fixes 2D IK
This commit is contained in:
@@ -715,26 +715,16 @@ Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2
|
|||||||
return (p_control->get_transform().xform(position) - parent_rect.position) / parent_rect.size;
|
return (p_control->get_transform().xform(position) - parent_rect.position) / parent_rect.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
|
void CanvasItemEditor::_save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state) {
|
||||||
for (List<CanvasItem *>::Element *E = p_canvas_items.front(); E; E = E->next()) {
|
if (p_bones_length)
|
||||||
CanvasItem *canvas_item = E->get();
|
*p_bones_length = List<float>();
|
||||||
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
if (p_bones_state)
|
||||||
if (se) {
|
*p_bones_state = List<Dictionary>();
|
||||||
se->undo_state = canvas_item->_edit_get_state();
|
|
||||||
se->pre_drag_xform = canvas_item->get_global_transform_with_canvas();
|
|
||||||
if (canvas_item->_edit_use_rect()) {
|
|
||||||
se->pre_drag_rect = canvas_item->_edit_get_rect();
|
|
||||||
} else {
|
|
||||||
se->pre_drag_rect = Rect2();
|
|
||||||
}
|
|
||||||
se->pre_drag_bones_length = List<float>();
|
|
||||||
se->pre_drag_bones_undo_state = List<Dictionary>();
|
|
||||||
|
|
||||||
// If we have a bone, save the state of all nodes in the IK chain
|
const Node2D *bone = Object::cast_to<Node2D>(p_canvas_item);
|
||||||
Node2D *bone = Object::cast_to<Node2D>(canvas_item);
|
|
||||||
if (bone && bone->has_meta("_edit_bone_")) {
|
if (bone && bone->has_meta("_edit_bone_")) {
|
||||||
// Check if we have an IK chain
|
// Check if we have an IK chain
|
||||||
List<Node2D *> bone_ik_list;
|
List<const Node2D *> bone_ik_list;
|
||||||
bool ik_found = false;
|
bool ik_found = false;
|
||||||
bone = Object::cast_to<Node2D>(bone->get_parent());
|
bone = Object::cast_to<Node2D>(bone->get_parent());
|
||||||
while (bone) {
|
while (bone) {
|
||||||
@@ -750,18 +740,45 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
|
|||||||
|
|
||||||
//Save the bone state and length if we have an IK chain
|
//Save the bone state and length if we have an IK chain
|
||||||
if (ik_found) {
|
if (ik_found) {
|
||||||
bone = Object::cast_to<Node2D>(canvas_item);
|
bone = Object::cast_to<Node2D>(p_canvas_item);
|
||||||
Transform2D bone_xform = bone->get_global_transform();
|
Transform2D bone_xform = bone->get_global_transform();
|
||||||
for (List<Node2D *>::Element *bone_E = bone_ik_list.front(); bone_E; bone_E = bone_E->next()) {
|
for (List<const Node2D *>::Element *bone_E = bone_ik_list.front(); bone_E; bone_E = bone_E->next()) {
|
||||||
bone_xform = bone_xform * bone->get_transform().affine_inverse();
|
bone_xform = bone_xform * bone->get_transform().affine_inverse();
|
||||||
Node2D *parent_bone = bone_E->get();
|
const Node2D *parent_bone = bone_E->get();
|
||||||
se->pre_drag_bones_length.push_back(parent_bone->get_global_transform().get_origin().distance_to(bone->get_global_position()));
|
if (p_bones_length)
|
||||||
se->pre_drag_bones_undo_state.push_back(parent_bone->_edit_get_state());
|
p_bones_length->push_back(parent_bone->get_global_transform().get_origin().distance_to(bone->get_global_position()));
|
||||||
|
if (p_bones_state)
|
||||||
|
p_bones_state->push_back(parent_bone->_edit_get_state());
|
||||||
bone = parent_bone;
|
bone = parent_bone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) {
|
||||||
|
for (List<CanvasItem *>::Element *E = p_canvas_items.front(); E; E = E->next()) {
|
||||||
|
CanvasItem *canvas_item = E->get();
|
||||||
|
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
||||||
|
if (se) {
|
||||||
|
se->undo_state = canvas_item->_edit_get_state();
|
||||||
|
se->pre_drag_xform = canvas_item->get_global_transform_with_canvas();
|
||||||
|
if (canvas_item->_edit_use_rect()) {
|
||||||
|
se->pre_drag_rect = canvas_item->_edit_get_rect();
|
||||||
|
} else {
|
||||||
|
se->pre_drag_rect = Rect2();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have a bone, save the state of all nodes in the IK chain
|
||||||
|
_save_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_length), &(se->pre_drag_bones_undo_state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanvasItemEditor::_restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state) {
|
||||||
|
CanvasItem *canvas_item = p_canvas_item;
|
||||||
|
for (const List<Dictionary>::Element *E = p_bones_state->front(); E; E = E->next()) {
|
||||||
|
canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
|
||||||
|
canvas_item->_edit_set_state(E->get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,10 +788,7 @@ void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_it
|
|||||||
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
||||||
canvas_item->_edit_set_state(se->undo_state);
|
canvas_item->_edit_set_state(se->undo_state);
|
||||||
if (restore_bones) {
|
if (restore_bones) {
|
||||||
for (List<Dictionary>::Element *E = se->pre_drag_bones_undo_state.front(); E; E = E->next()) {
|
_restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state));
|
||||||
canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
|
|
||||||
canvas_item->_edit_set_state(E->get());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1199,7 +1213,9 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
|
|||||||
|
|
||||||
void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) {
|
void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) {
|
||||||
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(leaf_node);
|
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(leaf_node);
|
||||||
if (se && !se->pre_drag_bones_undo_state.empty()) {
|
if (se) {
|
||||||
|
int nb_bones = se->pre_drag_bones_undo_state.size();
|
||||||
|
if (nb_bones > 0) {
|
||||||
|
|
||||||
// Build the node list
|
// Build the node list
|
||||||
Point2 leaf_pos = target_position;
|
Point2 leaf_pos = target_position;
|
||||||
@@ -1208,7 +1224,7 @@ void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) {
|
|||||||
List<Point2> joints_pos;
|
List<Point2> joints_pos;
|
||||||
Node2D *joint = leaf_node;
|
Node2D *joint = leaf_node;
|
||||||
Transform2D joint_transform = leaf_node->get_global_transform_with_canvas();
|
Transform2D joint_transform = leaf_node->get_global_transform_with_canvas();
|
||||||
for (int i = 0; i < se->pre_drag_bones_undo_state.size() + 1; i++) {
|
for (int i = 0; i < nb_bones + 1; i++) {
|
||||||
joints_list.push_back(joint);
|
joints_list.push_back(joint);
|
||||||
joints_pos.push_back(joint_transform.get_origin());
|
joints_pos.push_back(joint_transform.get_origin());
|
||||||
joint_transform = joint_transform * joint->get_transform().affine_inverse();
|
joint_transform = joint_transform * joint->get_transform().affine_inverse();
|
||||||
@@ -1253,7 +1269,6 @@ void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the position
|
// Set the position
|
||||||
float total_rot = 0.0f;
|
|
||||||
for (int node_id = joints_list.size() - 1; node_id > 0; node_id--) {
|
for (int node_id = joints_list.size() - 1; node_id > 0; node_id--) {
|
||||||
Point2 current = (joints_list[node_id - 1]->get_global_position() - joints_list[node_id]->get_global_position()).normalized();
|
Point2 current = (joints_list[node_id - 1]->get_global_position() - joints_list[node_id]->get_global_position()).normalized();
|
||||||
Point2 target = (joints_pos[node_id - 1] - joints_list[node_id]->get_global_position()).normalized();
|
Point2 target = (joints_pos[node_id - 1] - joints_list[node_id]->get_global_position()).normalized();
|
||||||
@@ -1262,10 +1277,8 @@ void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) {
|
|||||||
rot = -rot;
|
rot = -rot;
|
||||||
}
|
}
|
||||||
joints_list[node_id]->rotate(rot);
|
joints_list[node_id]->rotate(rot);
|
||||||
total_rot += rot;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
joints_list[0]->rotate(-total_rot);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1664,7 +1677,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
|
|||||||
if (drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
|
if (drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
|
||||||
// Resize the node
|
// Resize the node
|
||||||
if (m.is_valid()) {
|
if (m.is_valid()) {
|
||||||
_restore_canvas_item_state(drag_selection, true);
|
_restore_canvas_item_state(drag_selection);
|
||||||
CanvasItem *canvas_item = drag_selection[0];
|
CanvasItem *canvas_item = drag_selection[0];
|
||||||
|
|
||||||
drag_to = transform.affine_inverse().xform(m->get_position());
|
drag_to = transform.affine_inverse().xform(m->get_position());
|
||||||
@@ -1730,6 +1743,15 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
|
|||||||
if (drag_type == DRAG_MOVE) {
|
if (drag_type == DRAG_MOVE) {
|
||||||
// Move the nodes
|
// Move the nodes
|
||||||
if (m.is_valid()) {
|
if (m.is_valid()) {
|
||||||
|
|
||||||
|
// Save the ik chain for reapplying before IK solve
|
||||||
|
Vector<List<Dictionary> > all_bones_ik_states;
|
||||||
|
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
|
||||||
|
List<Dictionary> bones_ik_states;
|
||||||
|
_save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states);
|
||||||
|
all_bones_ik_states.push_back(bones_ik_states);
|
||||||
|
}
|
||||||
|
|
||||||
_restore_canvas_item_state(drag_selection, true);
|
_restore_canvas_item_state(drag_selection, true);
|
||||||
|
|
||||||
drag_to = transform.affine_inverse().xform(m->get_position());
|
drag_to = transform.affine_inverse().xform(m->get_position());
|
||||||
@@ -1751,6 +1773,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool force_no_IK = m->get_alt();
|
bool force_no_IK = m->get_alt();
|
||||||
|
int index = 0;
|
||||||
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
|
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
|
||||||
CanvasItem *canvas_item = E->get();
|
CanvasItem *canvas_item = E->get();
|
||||||
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
||||||
@@ -1758,10 +1781,15 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
|
|||||||
|
|
||||||
Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
|
Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
|
||||||
if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) {
|
if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) {
|
||||||
|
real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
|
||||||
|
_restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
|
||||||
|
real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
|
||||||
|
node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
|
||||||
_solve_IK(node2d, new_pos);
|
_solve_IK(node2d, new_pos);
|
||||||
} else {
|
} else {
|
||||||
canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
|
canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
|
||||||
}
|
}
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1800,6 +1828,14 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
|
|||||||
|
|
||||||
if (drag_selection.size() > 0) {
|
if (drag_selection.size() > 0) {
|
||||||
|
|
||||||
|
// Save the ik chain for reapplying before IK solve
|
||||||
|
Vector<List<Dictionary> > all_bones_ik_states;
|
||||||
|
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
|
||||||
|
List<Dictionary> bones_ik_states;
|
||||||
|
_save_canvas_item_ik_chain(E->get(), NULL, &bones_ik_states);
|
||||||
|
all_bones_ik_states.push_back(bones_ik_states);
|
||||||
|
}
|
||||||
|
|
||||||
_restore_canvas_item_state(drag_selection, true);
|
_restore_canvas_item_state(drag_selection, true);
|
||||||
|
|
||||||
bool move_local_base = k->get_alt();
|
bool move_local_base = k->get_alt();
|
||||||
@@ -1845,6 +1881,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
|
|||||||
new_pos = previous_pos + (drag_to - drag_from);
|
new_pos = previous_pos + (drag_to - drag_from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
|
for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) {
|
||||||
CanvasItem *canvas_item = E->get();
|
CanvasItem *canvas_item = E->get();
|
||||||
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
|
||||||
@@ -1852,10 +1889,15 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
|
|||||||
|
|
||||||
Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
|
Node2D *node2d = Object::cast_to<Node2D>(canvas_item);
|
||||||
if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
|
if (node2d && se->pre_drag_bones_undo_state.size() > 0) {
|
||||||
|
real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
|
||||||
|
_restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index]));
|
||||||
|
real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation();
|
||||||
|
node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation);
|
||||||
_solve_IK(node2d, new_pos);
|
_solve_IK(node2d, new_pos);
|
||||||
} else {
|
} else {
|
||||||
canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
|
canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
|
||||||
}
|
}
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -375,7 +375,9 @@ private:
|
|||||||
|
|
||||||
void _add_canvas_item(CanvasItem *p_canvas_item);
|
void _add_canvas_item(CanvasItem *p_canvas_item);
|
||||||
|
|
||||||
|
void _save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state);
|
||||||
void _save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones = false);
|
void _save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones = false);
|
||||||
|
void _restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state);
|
||||||
void _restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones = false);
|
void _restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones = false);
|
||||||
void _commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones = false);
|
void _commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones = false);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user