• Runtimes
  • Moving bones/IK's in GMS2 during runtime not working well

Related Discussions
...

I have a Spine character with a Gun IK that i want to follow the mouse cursor during runtime so that the character aims where he's shooting, i'm using GameMaker Studio 2 which i am aware does not have the best Spine support but this kind of stuff isn't new and should be working. As the worldX and worldY values of the bones are read only, i am left having to use the x and y values of the bones which if the manual is correct say are relative to the parent bone (which is still the root in this case).

I have uploaded a video illustrating the issue and would really appreciate some guidance:

When you specify x/y coordinates for a bone, the coordinates are relative to the bone's parent, not the world coordinate system. I'm afraid I'm not familiar with GM2s Spine API, but there should be a function that lets you convert from world coordinates (mouse cursor position) to local bone coordinates.

If you don't transform the root (it has rotation 0, scale is 1,1, and translation 0,0) then the skeleton's world coordinates and the root bone coordinates are the same. If you translate the root but it has rotation 0 and scale is 1,1 then you can subtract the root bone translation from a world position to get that position in root bone coordinates.

If rotate or scale the root bone, or your parent bone is deeper in the bone hierarchy, then you need to do the math to convert to that bone's coordinates. The Spine API to do that is Bone worldToLocal. I don't know what GM provides. You can also do the math yourself by multiplying the inverse of the world transform matrix.

3 роки пізніше

Know it's an old thread, but I ran into this exact same problem with GameMaker and was unable to find solutions posted anywhere, nor any tutorials that included functional code. I'm posting here in the event someone else finds it and is in need of a solution.

I tried to build a script based on the runtimes to convert coordinates as suggested above, but that made the problem even worse. Ultimately went to just solving it myself with what made logical sense to my brain. Surprisingly, it worked! 😉

This code assumes that the "aim_target" bone is parented directly to the root. No idea what would happen if your skeleton is set up otherwise. I placed this code in the Animation Update event of the object drawing the Spine animation. It tracks the mouse, and continues to track the mouse if the spine animation is rotated.

var root_map, aim_map, relative_mouse_x, relative_mouse_y, relative_mouse_angle, relative_mouse_distance, aim_target_x, aim_target_y; 

root_map = ds_map_create();
skeleton_bone_state_get("root", root_map);
aim_map = ds_map_create();
skeleton_bone_state_get("aim_target", aim_map);

relative_mouse_x      = mouse_x - ds_map_find_value(root_map, "worldX");
relative_mouse_y      = mouse_y - ds_map_find_value(root_map, "worldY");
relative_mouse_angle   = point_direction(ds_map_find_value(root_map, "worldX"), ds_map_find_value(root_map, "worldY"), mouse_x, mouse_y);
relative_mouse_distance = point_distance( ds_map_find_value(root_map, "x"),  ds_map_find_value(root_map, "y"), relative_mouse_x, relative_mouse_y  )

aim_target_x = (ds_map_find_value(root_map, "x") + lengthdir_x(relative_mouse_distance, relative_mouse_angle - ds_map_find_value(root_map, "angle"))) / image_xscale; 
aim_target_y = (ds_map_find_value(root_map, "y") + lengthdir_y(relative_mouse_distance, relative_mouse_angle - ds_map_find_value(root_map, "angle"))) / image_yscale * -1; 

ds_map_replace(aim_map, "x", aim_target_x);
ds_map_replace(aim_map, "y", aim_target_y);
skeleton_bone_state_set("aim_target", aim_map);

/* Use This To Display Bone Data for either "root_map" or "aim_map". Swap the names accordingly. Thanks Community!
var _next = ds_map_find_first( root_map );
var _count = 0;
while ( !is_undefined( _next ) ) {
  var _string = string( _next ) + "   " + string( root_map[? _next ] );
  show_debug_message("root_map: " + string( _string ));
  _next = ds_map_find_next( root_map, _next );
  _count++;
} */

ds_map_destroy(root_map);
ds_map_destroy(aim_map);

Edit: Changed + ds_map_find_value(root_map, "angle") to - ds_map_find_value(root_map, "angle") after the update to the GameMaker runtimes to 4.0. \o/

You have a good brain indeed! Thanks for posting your solution.